Home | History | Annotate | Download | only in pthread_self
      1 /*
      2  * Copyright (c) 2004, Bull S.A..  All rights reserved.
      3  * Created by: Sebastien Decugis
      4 
      5  * This program is free software; you can redistribute it and/or modify it
      6  * under the terms of version 2 of the GNU General Public License as
      7  * published by the Free Software Foundation.
      8  *
      9  * This program is distributed in the hope that it would be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     12  *
     13  * You should have received a copy of the GNU General Public License along
     14  * with this program; if not, write the Free Software Foundation, Inc.,
     15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     16 
     17  * This file is a helper file for the pthread_create tests
     18  * It defines the following objects:
     19  * scenarii: array of struct __scenario type.
     20  * NSCENAR : macro giving the total # of scenarii
     21  * scenar_init(): function to call before use the scenarii array.
     22  * scenar_fini(): function to call after end of use of the scenarii array.
     23  *
     24  */
     25 
     26 struct __scenario {
     27 	/* Object to hold the given configuration, and which will be used to create the threads */
     28 	pthread_attr_t ta;
     29 	/* General parameters */
     30 	int detached;		/* 0 => joinable; 1 => detached */
     31 	/* Scheduling parameters */
     32 	int explicitsched;	/* 0 => sched policy is inherited; 1 => sched policy from the attr param */
     33 	int schedpolicy;	/* 0 => default; 1=> SCHED_FIFO; 2=> SCHED_RR */
     34 	int schedparam;		/* 0 => default sched param; 1 => max value for sched param; -1 => min value for sched param */
     35 	int altscope;		/* 0 => default contension scope; 1 => alternative contension scope */
     36 	/* Stack parameters */
     37 	int altstack;		/* 0 => system manages the stack; 1 => stack is provided */
     38 	int guard;		/* 0 => default guardsize; 1=> guardsize is 0; 2=> guard is 1 page -- this setting only affect system stacks (not user's). */
     39 	int altsize;		/* 0 => default stack size; 1 => stack size specified (min value) -- ignored when stack is provided */
     40 	/* Additionnal information */
     41 	char *descr;		/* object description */
     42 	void *bottom;		/* Stores the stack start when an alternate stack is required */
     43 	int result;		/* This thread creation is expected to: 0 => succeed; 1 => fail; 2 => unknown */
     44 	sem_t sem;		/* This semaphore is used to signal the end of the detached threads execution */
     45 } scenarii[] =
     46 #define CASE(det,expl,scp,spa,sco,sta,gua,ssi,desc,res) \
     47  { \
     48 	 .detached=det, \
     49 	 .explicitsched=expl, \
     50 	 .schedpolicy=scp, \
     51 	 .schedparam=spa, \
     52  	 .altscope=sco, \
     53  	 .altstack=sta, \
     54  	 .guard=gua, \
     55  	 .altsize=ssi, \
     56  	 .descr=desc, \
     57  	 .bottom=NULL, \
     58 	 .result=res }
     59 #define CASE_POS(det,expl,scp,spa,sco,sta,gua,ssi,desc) CASE(det,expl,scp,spa,sco,sta,gua,ssi,desc,0)
     60 #define CASE_NEG(det,expl,scp,spa,sco,sta,gua,ssi,desc) CASE(det,expl,scp,spa,sco,sta,gua,ssi,desc,1)
     61 #define CASE_UNK(det,expl,scp,spa,sco,sta,gua,ssi,desc) CASE(det,expl,scp,spa,sco,sta,gua,ssi,desc,2)
     62     /*
     63      * This array gives the different combinations of threads attributes for the testcases.
     64      *
     65      * Some combinations must be avoided.
     66      * -> Do not have a detached thread use an alternative stack;
     67      *     as we don't know when the thread terminates to free the stack memory
     68      * -> ... (to be completed)
     69      *
     70      */
     71 {
     72 	/* Unary tests */
     73 /* 0*/ CASE_POS(0, 0, 0, 0, 0, 0, 0, 0, "default")
     74 
     75 /* 1*/
     76 	    , CASE_POS(1, 0, 0, 0, 0, 0, 0, 0, "detached")
     77 /* 2*/
     78 	    , CASE_POS(0, 1, 0, 0, 0, 0, 0, 0, "Explicit sched")
     79 /* 3*/
     80 	    , CASE_UNK(0, 0, 1, 0, 0, 0, 0, 0, "FIFO Policy")
     81 /* 4*/
     82 	    , CASE_UNK(0, 0, 2, 0, 0, 0, 0, 0, "RR Policy")
     83 /* 5*/
     84 	    , CASE_UNK(0, 0, 0, 1, 0, 0, 0, 0, "Max sched param")
     85 /* 6*/
     86 	    , CASE_UNK(0, 0, 0, -1, 0, 0, 0, 0, "Min sched param")
     87 /* 7*/
     88 	    , CASE_POS(0, 0, 0, 0, 1, 0, 0, 0, "Alternative contension scope")
     89 /* 8*/
     90 	    , CASE_POS(0, 0, 0, 0, 0, 1, 0, 0, "Alternative stack")
     91 /* 9*/
     92 	    , CASE_POS(0, 0, 0, 0, 0, 0, 1, 0, "No guard size")
     93 /*10*/
     94 	    , CASE_UNK(0, 0, 0, 0, 0, 0, 2, 0, "1p guard size")
     95 /*11*/
     96 	    , CASE_POS(0, 0, 0, 0, 0, 0, 0, 1, "Min stack size")
     97 
     98 /* We create several instances of the basic cases for the pthread_self testing */
     99 /* 0*/ , CASE_POS(0, 0, 0, 0, 0, 0, 0, 0, "default")
    100 /* 1*/
    101 	    , CASE_POS(1, 0, 0, 0, 0, 0, 0, 0, "detached")
    102 /* 2*/
    103 	    , CASE_POS(0, 1, 0, 0, 0, 0, 0, 0, "Explicit sched")
    104 /* 3*/
    105 	    , CASE_UNK(0, 0, 1, 0, 0, 0, 0, 0, "FIFO Policy")
    106 /* 4*/
    107 	    , CASE_UNK(0, 0, 2, 0, 0, 0, 0, 0, "RR Policy")
    108 /* 5*/
    109 	    , CASE_UNK(0, 0, 0, 1, 0, 0, 0, 0, "Max sched param")
    110 /* 6*/
    111 	    , CASE_UNK(0, 0, 0, -1, 0, 0, 0, 0, "Min sched param")
    112 /* 7*/
    113 	    , CASE_POS(0, 0, 0, 0, 1, 0, 0, 0, "Alternative contension scope")
    114 	    /* 8*//*,CASE_POS(0, 0, 0, 0, 0, 1, 0, 0, "Alternative stack") */
    115 /* 9*/ , CASE_POS(0, 0, 0, 0, 0, 0, 1, 0, "No guard size")
    116 /*10*/
    117 	    , CASE_UNK(0, 0, 0, 0, 0, 0, 2, 0, "1p guard size")
    118 /*11*/
    119 	    , CASE_POS(0, 0, 0, 0, 0, 0, 0, 1, "Min stack size")
    120 /* 0*/
    121 	    , CASE_POS(0, 0, 0, 0, 0, 0, 0, 0, "default")
    122 /* 1*/
    123 	    , CASE_POS(1, 0, 0, 0, 0, 0, 0, 0, "detached")
    124 /* 2*/
    125 	    , CASE_POS(0, 1, 0, 0, 0, 0, 0, 0, "Explicit sched")
    126 /* 3*/
    127 	    , CASE_UNK(0, 0, 1, 0, 0, 0, 0, 0, "FIFO Policy")
    128 /* 4*/
    129 	    , CASE_UNK(0, 0, 2, 0, 0, 0, 0, 0, "RR Policy")
    130 /* 5*/
    131 	    , CASE_UNK(0, 0, 0, 1, 0, 0, 0, 0, "Max sched param")
    132 /* 6*/
    133 	    , CASE_UNK(0, 0, 0, -1, 0, 0, 0, 0, "Min sched param")
    134 /* 7*/
    135 	    , CASE_POS(0, 0, 0, 0, 1, 0, 0, 0, "Alternative contension scope")
    136 	    /* 8*//*,CASE_POS(0, 0, 0, 0, 0, 1, 0, 0, "Alternative stack") */
    137 /* 9*/ , CASE_POS(0, 0, 0, 0, 0, 0, 1, 0, "No guard size")
    138 /*10*/
    139 	    , CASE_UNK(0, 0, 0, 0, 0, 0, 2, 0, "1p guard size")
    140 /*11*/
    141 	    , CASE_POS(0, 0, 0, 0, 0, 0, 0, 1, "Min stack size")
    142 /* 0*/
    143 	    , CASE_POS(0, 0, 0, 0, 0, 0, 0, 0, "default")
    144 /* 1*/
    145 	    , CASE_POS(1, 0, 0, 0, 0, 0, 0, 0, "detached")
    146 /* 2*/
    147 	    , CASE_POS(0, 1, 0, 0, 0, 0, 0, 0, "Explicit sched")
    148 /* 3*/
    149 	    , CASE_UNK(0, 0, 1, 0, 0, 0, 0, 0, "FIFO Policy")
    150 /* 4*/
    151 	    , CASE_UNK(0, 0, 2, 0, 0, 0, 0, 0, "RR Policy")
    152 /* 5*/
    153 	    , CASE_UNK(0, 0, 0, 1, 0, 0, 0, 0, "Max sched param")
    154 /* 6*/
    155 	    , CASE_UNK(0, 0, 0, -1, 0, 0, 0, 0, "Min sched param")
    156 /* 7*/
    157 	    , CASE_POS(0, 0, 0, 0, 1, 0, 0, 0, "Alternative contension scope")
    158 	    /* 8*//*,CASE_POS(0, 0, 0, 0, 0, 1, 0, 0, "Alternative stack") */
    159 /* 9*/ , CASE_POS(0, 0, 0, 0, 0, 0, 1, 0, "No guard size")
    160 /*10*/
    161 	    , CASE_UNK(0, 0, 0, 0, 0, 0, 2, 0, "1p guard size")
    162 /*11*/
    163 	    , CASE_POS(0, 0, 0, 0, 0, 0, 0, 1, "Min stack size")
    164 
    165 	    /* Stack play */
    166 	    , CASE_POS(0, 0, 0, 0, 0, 0, 1, 1, "Min stack size, no guard")
    167 	    , CASE_UNK(0, 0, 0, 0, 0, 0, 2, 1, "Min stack size, 1p guard")
    168 	    /*,CASE_POS(1, 0, 0, 0, 0, 1, 0, 0, "Detached, Alternative stack") */
    169 	    , CASE_POS(1, 0, 0, 0, 0, 0, 1, 1,
    170 		       "Detached, Min stack size, no guard")
    171 	    , CASE_UNK(1, 0, 0, 0, 0, 0, 2, 1,
    172 		       "Detached, Min stack size, 1p guard")
    173 
    174 	    /* Scheduling play -- all results are unknown since it might depend on the user priviledges */
    175 	    , CASE_UNK(0, 1, 1, 1, 0, 0, 0, 0, "Explicit FIFO max param")
    176 	    , CASE_UNK(0, 1, 2, 1, 0, 0, 0, 0, "Explicit RR max param")
    177 	    , CASE_UNK(0, 1, 1, -1, 0, 0, 0, 0, "Explicit FIFO min param")
    178 	    , CASE_UNK(0, 1, 2, -1, 0, 0, 0, 0, "Explicit RR min param")
    179 	    , CASE_UNK(0, 1, 1, 1, 1, 0, 0, 0,
    180 		       "Explicit FIFO max param, alt scope")
    181 	    , CASE_UNK(0, 1, 2, 1, 1, 0, 0, 0,
    182 		       "Explicit RR max param, alt scope")
    183 	    , CASE_UNK(0, 1, 1, -1, 1, 0, 0, 0,
    184 		       "Explicit FIFO min param, alt scope")
    185 	    , CASE_UNK(0, 1, 2, -1, 1, 0, 0, 0,
    186 		       "Explicit RR min param, alt scope")
    187 	    , CASE_UNK(1, 1, 1, 1, 0, 0, 0, 0,
    188 		       "Detached, explicit FIFO max param")
    189 	    , CASE_UNK(1, 1, 2, 1, 0, 0, 0, 0,
    190 		       "Detached, explicit RR max param")
    191 	    , CASE_UNK(1, 1, 1, -1, 0, 0, 0, 0,
    192 		       "Detached, explicit FIFO min param")
    193 	    , CASE_UNK(1, 1, 2, -1, 0, 0, 0, 0,
    194 		       "Detached, explicit RR min param")
    195 	    , CASE_UNK(1, 1, 1, 1, 1, 0, 0, 0,
    196 		       "Detached, explicit FIFO max param, alt scope")
    197 	    , CASE_UNK(1, 1, 2, 1, 1, 0, 0, 0,
    198 		       "Detached, explicit RR max param, alt scope")
    199 	    , CASE_UNK(1, 1, 1, -1, 1, 0, 0, 0,
    200 		       "Detached, explicit FIFO min param, alt scope")
    201 	    , CASE_UNK(1, 1, 2, -1, 1, 0, 0, 0,
    202 		       "Detached, explicit RR min param, alt scope")
    203 };
    204 
    205 #define NSCENAR (sizeof(scenarii) / sizeof(scenarii[0]))
    206 
    207 /* This function will initialize every pthread_attr_t object in the scenarii array */
    208 void scenar_init()
    209 {
    210 	int ret = 0;
    211 	int i;
    212 	int old;
    213 	long pagesize, minstacksize;
    214 	long tsa, tss, tps;
    215 
    216 	pagesize = sysconf(_SC_PAGESIZE);
    217 	minstacksize = sysconf(_SC_THREAD_STACK_MIN);
    218 	tsa = sysconf(_SC_THREAD_ATTR_STACKADDR);
    219 	tss = sysconf(_SC_THREAD_ATTR_STACKSIZE);
    220 	tps = sysconf(_SC_THREAD_PRIORITY_SCHEDULING);
    221 
    222 #if VERBOSE > 0
    223 	output("System abilities:\n");
    224 	output(" TSA: %li\n", tsa);
    225 	output(" TSS: %li\n", tss);
    226 	output(" TPS: %li\n", tps);
    227 	output(" pagesize: %li\n", pagesize);
    228 	output(" min stack size: %li\n", minstacksize);
    229 #endif
    230 
    231 	if (minstacksize % pagesize) {
    232 		UNTESTED
    233 		    ("The min stack size is not a multiple of the page size");
    234 	}
    235 
    236 	for (i = 0; i < NSCENAR; i++) {
    237 #if VERBOSE > 2
    238 		output("Initializing attribute for scenario %i: %s\n", i,
    239 		       scenarii[i].descr);
    240 #endif
    241 
    242 		ret = pthread_attr_init(&scenarii[i].ta);
    243 		if (ret != 0) {
    244 			UNRESOLVED(ret,
    245 				   "Failed to initialize a thread attribute object");
    246 		}
    247 
    248 		/* Set the attributes according to the scenario */
    249 		if (scenarii[i].detached == 1) {
    250 			ret =
    251 			    pthread_attr_setdetachstate(&scenarii[i].ta,
    252 							PTHREAD_CREATE_DETACHED);
    253 			if (ret != 0) {
    254 				UNRESOLVED(ret, "Unable to set detachstate");
    255 			}
    256 		} else {
    257 			ret =
    258 			    pthread_attr_getdetachstate(&scenarii[i].ta, &old);
    259 			if (ret != 0) {
    260 				UNRESOLVED(ret,
    261 					   "Unable to get detachstate from initialized attribute");
    262 			}
    263 			if (old != PTHREAD_CREATE_JOINABLE) {
    264 				FAILED
    265 				    ("The default attribute is not PTHREAD_CREATE_JOINABLE");
    266 			}
    267 		}
    268 #if VERBOSE > 4
    269 		output("Detach state was set sucessfully\n");
    270 #endif
    271 
    272 		/* Sched related attributes */
    273 		if (tps > 0) {	/* This routine is dependent on the Thread Execution Scheduling option */
    274 			if (scenarii[i].explicitsched == 1)
    275 				ret =
    276 				    pthread_attr_setinheritsched(&scenarii[i].
    277 								 ta,
    278 								 PTHREAD_EXPLICIT_SCHED);
    279 			else
    280 				ret =
    281 				    pthread_attr_setinheritsched(&scenarii[i].
    282 								 ta,
    283 								 PTHREAD_INHERIT_SCHED);
    284 			if (ret != 0) {
    285 				UNRESOLVED(ret,
    286 					   "Unable to set inheritsched attribute");
    287 			}
    288 #if VERBOSE > 4
    289 			output("inheritsched state was set sucessfully\n");
    290 #endif
    291 		}
    292 #if VERBOSE > 4
    293 		else
    294 			output
    295 			    ("TPS unsupported => inheritsched parameter untouched\n");
    296 #endif
    297 
    298 		if (tps > 0) {	/* This routine is dependent on the Thread Execution Scheduling option */
    299 			if (scenarii[i].schedpolicy == 1) {
    300 				ret =
    301 				    pthread_attr_setschedpolicy(&scenarii[i].ta,
    302 								SCHED_FIFO);
    303 			}
    304 			if (scenarii[i].schedpolicy == 2) {
    305 				ret =
    306 				    pthread_attr_setschedpolicy(&scenarii[i].ta,
    307 								SCHED_RR);
    308 			}
    309 			if (ret != 0) {
    310 				UNRESOLVED(ret,
    311 					   "Unable to set the sched policy");
    312 			}
    313 #if VERBOSE > 4
    314 			if (scenarii[i].schedpolicy)
    315 				output("Sched policy was set sucessfully\n");
    316 			else
    317 				output("Sched policy untouched\n");
    318 #endif
    319 		}
    320 #if VERBOSE > 4
    321 		else
    322 			output
    323 			    ("TPS unsupported => sched policy parameter untouched\n");
    324 #endif
    325 
    326 		if (scenarii[i].schedparam != 0) {
    327 			struct sched_param sp;
    328 
    329 			ret =
    330 			    pthread_attr_getschedpolicy(&scenarii[i].ta, &old);
    331 			if (ret != 0) {
    332 				UNRESOLVED(ret,
    333 					   "Unable to get sched policy from attribute");
    334 			}
    335 
    336 			if (scenarii[i].schedparam == 1)
    337 				sp.sched_priority = sched_get_priority_max(old);
    338 			if (scenarii[i].schedparam == -1)
    339 				sp.sched_priority = sched_get_priority_min(old);
    340 
    341 			ret = pthread_attr_setschedparam(&scenarii[i].ta, &sp);
    342 			if (ret != 0) {
    343 				UNRESOLVED(ret,
    344 					   "Failed to set the sched param");
    345 			}
    346 #if VERBOSE > 4
    347 			output("Sched param was set sucessfully to %i\n",
    348 			       sp.sched_priority);
    349 		} else {
    350 			output("Sched param untouched\n");
    351 #endif
    352 		}
    353 
    354 		if (tps > 0) {	/* This routine is dependent on the Thread Execution Scheduling option */
    355 			ret = pthread_attr_getscope(&scenarii[i].ta, &old);
    356 			if (ret != 0) {
    357 				UNRESOLVED(ret,
    358 					   "Failed to get contension scope from thread attribute");
    359 			}
    360 
    361 			if (scenarii[i].altscope != 0) {
    362 				if (old == PTHREAD_SCOPE_PROCESS)
    363 					old = PTHREAD_SCOPE_SYSTEM;
    364 				else
    365 					old = PTHREAD_SCOPE_PROCESS;
    366 
    367 				ret =
    368 				    pthread_attr_setscope(&scenarii[i].ta, old);
    369 				//if (ret != 0)  {  UNRESOLVED(ret, "Failed to set contension scope");  }
    370 #if VERBOSE > 0
    371 				if (ret != 0) {
    372 					output
    373 					    ("WARNING: The TPS option is claimed to be supported but setscope fails\n");
    374 				}
    375 #endif
    376 
    377 #if VERBOSE > 4
    378 				output("Contension scope set to %s\n",
    379 				       old ==
    380 				       PTHREAD_SCOPE_PROCESS ?
    381 				       "PTHREAD_SCOPE_PROCESS" :
    382 				       "PTHREAD_SCOPE_SYSTEM");
    383 			} else {
    384 				output("Contension scope untouched (%s)\n",
    385 				       old ==
    386 				       PTHREAD_SCOPE_PROCESS ?
    387 				       "PTHREAD_SCOPE_PROCESS" :
    388 				       "PTHREAD_SCOPE_SYSTEM");
    389 #endif
    390 			}
    391 		}
    392 #if VERBOSE > 4
    393 		else
    394 			output
    395 			    ("TPS unsupported => sched contension scope parameter untouched\n");
    396 #endif
    397 
    398 		/* Stack related attributes */
    399 		if ((tss > 0) && (tsa > 0)) {	/* This routine is dependent on the Thread Stack Address Attribute
    400 						   and Thread Stack Size Attribute options */
    401 			if (scenarii[i].altstack != 0) {
    402 				/* This is slightly more complicated. We need to alloc a new stack
    403 				   and free it upon test termination */
    404 				/* We will alloc with a simulated guardsize of 1 pagesize */
    405 				scenarii[i].bottom = malloc(minstacksize + pagesize);
    406 				if (scenarii[i].bottom == NULL) {
    407 					UNRESOLVED(errno,
    408 						   "Unable to alloc enough memory for alternative stack");
    409 				}
    410 
    411 				ret =
    412 				    pthread_attr_setstack(&scenarii[i].ta,
    413 							  scenarii[i].bottom,
    414 							  minstacksize);
    415 				if (ret != 0) {
    416 					UNRESOLVED(ret,
    417 						   "Failed to specify alternate stack");
    418 				}
    419 #if VERBOSE > 1
    420 				output
    421 				    ("Alternate stack created successfully. Bottom=%p, Size=%i\n",
    422 				     scenarii[i].bottom, minstacksize);
    423 #endif
    424 			}
    425 		}
    426 #if VERBOSE > 4
    427 		else
    428 			output
    429 			    ("TSA or TSS unsupported => No alternative stack\n");
    430 #endif
    431 
    432 #ifndef WITHOUT_XOPEN
    433 		if (scenarii[i].guard != 0) {
    434 			if (scenarii[i].guard == 1)
    435 				ret =
    436 				    pthread_attr_setguardsize(&scenarii[i].ta,
    437 							      0);
    438 			if (scenarii[i].guard == 2)
    439 				ret =
    440 				    pthread_attr_setguardsize(&scenarii[i].ta,
    441 							      pagesize);
    442 			if (ret != 0) {
    443 				UNRESOLVED(ret,
    444 					   "Unable to set guard area size in thread stack");
    445 			}
    446 #if VERBOSE > 4
    447 			output("Guard size set to %i\n",
    448 			       (scenarii[i].guard == 1) ? 1 : pagesize);
    449 #endif
    450 		}
    451 #endif
    452 
    453 		if (tss > 0) {	/* This routine is dependent on the Thread Stack Size Attribute option */
    454 			if (scenarii[i].altsize != 0) {
    455 				ret =
    456 				    pthread_attr_setstacksize(&scenarii[i].ta,
    457 							      minstacksize);
    458 				if (ret != 0) {
    459 					UNRESOLVED(ret,
    460 						   "Unable to change stack size");
    461 				}
    462 #if VERBOSE > 4
    463 				output
    464 				    ("Stack size set to %i (this is the min)\n",
    465 				     minstacksize);
    466 #endif
    467 			}
    468 		}
    469 #if VERBOSE > 4
    470 		else
    471 			output("TSS unsupported => stack size unchanged\n");
    472 #endif
    473 
    474 		ret = sem_init(&scenarii[i].sem, 0, 0);
    475 		if (ret == -1) {
    476 			UNRESOLVED(errno, "Unable to init a semaphore");
    477 		}
    478 
    479 	}
    480 #if VERBOSE > 0
    481 	output("All %i thread attribute objects were initialized\n\n", NSCENAR);
    482 #endif
    483 }
    484 
    485 /* This function will free all resources consumed in the scenar_init() routine */
    486 void scenar_fini(void)
    487 {
    488 	int ret = 0, i;
    489 
    490 	for (i = 0; i < NSCENAR; i++) {
    491 		if (scenarii[i].bottom != NULL)
    492 			free(scenarii[i].bottom);
    493 
    494 		ret = sem_destroy(&scenarii[i].sem);
    495 		if (ret == -1) {
    496 			UNRESOLVED(errno, "Unable to destroy a semaphore");
    497 		}
    498 
    499 		ret = pthread_attr_destroy(&scenarii[i].ta);
    500 		if (ret != 0) {
    501 			UNRESOLVED(ret,
    502 				   "Failed to destroy a thread attribute object");
    503 		}
    504 	}
    505 }
    506 
    507 int sc = 0;			/* This might be very dirty... but is much simpler */
    508 
    509 #ifdef STD_MAIN			/* We want main to be defined here */
    510 
    511 extern void *threaded(void *arg);	/* This is the test function */
    512 
    513 int main(int argc, char *argv[])
    514 {
    515 	int ret = 0;
    516 	pthread_t child;
    517 
    518 	/* Initialize output routine */
    519 	output_init();
    520 
    521 	/* Initialize thread attribute objects */
    522 	scenar_init();
    523 
    524 	for (sc = 0; sc < NSCENAR; sc++) {
    525 #if VERBOSE > 0
    526 		output("-----\n");
    527 		output("Starting test with scenario (%i): %s\n", sc,
    528 		       scenarii[sc].descr);
    529 #endif
    530 
    531 		ret = pthread_create(&child, &scenarii[sc].ta, threaded, NULL);
    532 		switch (scenarii[sc].result) {
    533 		case 0:	/* Operation was expected to succeed */
    534 			if (ret != 0) {
    535 				UNRESOLVED(ret, "Failed to create this thread");
    536 			}
    537 			break;
    538 
    539 		case 1:	/* Operation was expected to fail */
    540 			if (ret == 0) {
    541 				UNRESOLVED(-1,
    542 					   "An error was expected but the thread creation succeeded");
    543 			}
    544 			break;
    545 
    546 		case 2:	/* We did not know the expected result */
    547 		default:
    548 #if VERBOSE > 0
    549 			if (ret == 0) {
    550 				output
    551 				    ("Thread has been created successfully for this scenario\n");
    552 			} else {
    553 				output
    554 				    ("Thread creation failed with the error: %s\n",
    555 				     strerror(ret));
    556 			}
    557 #endif
    558 		}
    559 		if (ret == 0) {	/* The new thread is running */
    560 			if (scenarii[sc].detached == 0) {
    561 				ret = pthread_join(child, NULL);
    562 				if (ret != 0) {
    563 					UNRESOLVED(ret,
    564 						   "Unable to join a thread");
    565 				}
    566 			} else {
    567 				/* Just wait for the thread to terminate */
    568 				do {
    569 					ret = sem_wait(&scenarii[sc].sem);
    570 				}
    571 				while ((ret == -1) && (errno == EINTR));
    572 				if (ret == -1) {
    573 					UNRESOLVED(errno,
    574 						   "Failed to wait for the semaphore");
    575 				}
    576 			}
    577 		}
    578 	}
    579 
    580 	scenar_fini();
    581 #if VERBOSE > 0
    582 	output("-----\n");
    583 	output("All test data destroyed\n");
    584 	output("Test PASSED\n");
    585 #endif
    586 
    587 	PASSED;
    588 }
    589 #endif
    590