Home | History | Annotate | Download | only in pthread_exit
      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 /* 1*/
     75 	    , CASE_POS(1, 0, 0, 0, 0, 0, 0, 0, "detached")
     76 /* 2*/
     77 	    , CASE_POS(0, 1, 0, 0, 0, 0, 0, 0, "Explicit sched")
     78 /* 3*/
     79 	    , CASE_UNK(0, 0, 1, 0, 0, 0, 0, 0, "FIFO Policy")
     80 /* 4*/
     81 	    , CASE_UNK(0, 0, 2, 0, 0, 0, 0, 0, "RR Policy")
     82 /* 5*/
     83 	    , CASE_UNK(0, 0, 0, 1, 0, 0, 0, 0, "Max sched param")
     84 /* 6*/
     85 	    , CASE_UNK(0, 0, 0, -1, 0, 0, 0, 0, "Min sched param")
     86 /* 7*/
     87 	    , CASE_POS(0, 0, 0, 0, 1, 0, 0, 0, "Alternative contension scope")
     88 /* 8*/
     89 	    , CASE_POS(0, 0, 0, 0, 0, 1, 0, 0, "Alternative stack")
     90 /* 9*/
     91 	    , CASE_POS(0, 0, 0, 0, 0, 0, 1, 0, "No guard size")
     92 /*10*/
     93 	    , CASE_UNK(0, 0, 0, 0, 0, 0, 2, 0, "1p guard size")
     94 /*11*/
     95 	    , CASE_POS(0, 0, 0, 0, 0, 0, 0, 1, "Min stack size")
     96 
     97 	    /* Stack play */
     98 	    , CASE_POS(0, 0, 0, 0, 0, 0, 1, 1, "Min stack size, no guard")
     99 	    , CASE_UNK(0, 0, 0, 0, 0, 0, 2, 1, "Min stack size, 1p guard")
    100 	    , CASE_POS(1, 0, 0, 0, 0, 1, 0, 0, "Detached, Alternative stack")
    101 	    , CASE_POS(1, 0, 0, 0, 0, 0, 1, 1,
    102 		       "Detached, Min stack size, no guard")
    103 	    , CASE_UNK(1, 0, 0, 0, 0, 0, 2, 1,
    104 		       "Detached, Min stack size, 1p guard")
    105 
    106 	    /* Scheduling play -- all results are unknown since it might depend on the user priviledges */
    107 	    , CASE_UNK(0, 1, 1, 1, 0, 0, 0, 0, "Explicit FIFO max param")
    108 	    , CASE_UNK(0, 1, 2, 1, 0, 0, 0, 0, "Explicit RR max param")
    109 	    , CASE_UNK(0, 1, 1, -1, 0, 0, 0, 0, "Explicit FIFO min param")
    110 	    , CASE_UNK(0, 1, 2, -1, 0, 0, 0, 0, "Explicit RR min param")
    111 	    , CASE_UNK(0, 1, 1, 1, 1, 0, 0, 0,
    112 		       "Explicit FIFO max param, alt scope")
    113 	    , CASE_UNK(0, 1, 2, 1, 1, 0, 0, 0,
    114 		       "Explicit RR max param, alt scope")
    115 	    , CASE_UNK(0, 1, 1, -1, 1, 0, 0, 0,
    116 		       "Explicit FIFO min param, alt scope")
    117 	    , CASE_UNK(0, 1, 2, -1, 1, 0, 0, 0,
    118 		       "Explicit RR min param, alt scope")
    119 	    , CASE_UNK(1, 1, 1, 1, 0, 0, 0, 0,
    120 		       "Detached, explicit FIFO max param")
    121 	    , CASE_UNK(1, 1, 2, 1, 0, 0, 0, 0,
    122 		       "Detached, explicit RR max param")
    123 	    , CASE_UNK(1, 1, 1, -1, 0, 0, 0, 0,
    124 		       "Detached, explicit FIFO min param")
    125 	    , CASE_UNK(1, 1, 2, -1, 0, 0, 0, 0,
    126 		       "Detached, explicit RR min param")
    127 	    , CASE_UNK(1, 1, 1, 1, 1, 0, 0, 0,
    128 		       "Detached, explicit FIFO max param, alt scope")
    129 	    , CASE_UNK(1, 1, 2, 1, 1, 0, 0, 0,
    130 		       "Detached, explicit RR max param, alt scope")
    131 	    , CASE_UNK(1, 1, 1, -1, 1, 0, 0, 0,
    132 		       "Detached, explicit FIFO min param, alt scope")
    133 	    , CASE_UNK(1, 1, 2, -1, 1, 0, 0, 0,
    134 		       "Detached, explicit RR min param, alt scope")
    135 
    136 };
    137 
    138 #define NSCENAR (sizeof(scenarii) / sizeof(scenarii[0]))
    139 
    140 /* This function will initialize every pthread_attr_t object in the scenarii array */
    141 void scenar_init()
    142 {
    143 	int ret = 0;
    144 	int i;
    145 	int old;
    146 	long pagesize, minstacksize;
    147 	long tsa, tss, tps;
    148 
    149 	pagesize = sysconf(_SC_PAGESIZE);
    150 	minstacksize = sysconf(_SC_THREAD_STACK_MIN);
    151 	tsa = sysconf(_SC_THREAD_ATTR_STACKADDR);
    152 	tss = sysconf(_SC_THREAD_ATTR_STACKSIZE);
    153 	tps = sysconf(_SC_THREAD_PRIORITY_SCHEDULING);
    154 
    155 #if VERBOSE > 0
    156 	output("System abilities:\n");
    157 	output(" TSA: %li\n", tsa);
    158 	output(" TSS: %li\n", tss);
    159 	output(" TPS: %li\n", tps);
    160 	output(" pagesize: %li\n", pagesize);
    161 	output(" min stack size: %li\n", minstacksize);
    162 #endif
    163 
    164 	if (minstacksize % pagesize) {
    165 		UNTESTED
    166 		    ("The min stack size is not a multiple of the page size");
    167 	}
    168 
    169 	for (i = 0; i < NSCENAR; i++) {
    170 #if VERBOSE > 2
    171 		output("Initializing attribute for scenario %i: %s\n", i,
    172 		       scenarii[i].descr);
    173 #endif
    174 
    175 		ret = pthread_attr_init(&scenarii[i].ta);
    176 		if (ret != 0) {
    177 			UNRESOLVED(ret,
    178 				   "Failed to initialize a thread attribute object");
    179 		}
    180 
    181 		/* Set the attributes according to the scenario */
    182 		if (scenarii[i].detached == 1) {
    183 			ret =
    184 			    pthread_attr_setdetachstate(&scenarii[i].ta,
    185 							PTHREAD_CREATE_DETACHED);
    186 			if (ret != 0) {
    187 				UNRESOLVED(ret, "Unable to set detachstate");
    188 			}
    189 		} else {
    190 			ret =
    191 			    pthread_attr_getdetachstate(&scenarii[i].ta, &old);
    192 			if (ret != 0) {
    193 				UNRESOLVED(ret,
    194 					   "Unable to get detachstate from initialized attribute");
    195 			}
    196 			if (old != PTHREAD_CREATE_JOINABLE) {
    197 				FAILED
    198 				    ("The default attribute is not PTHREAD_CREATE_JOINABLE");
    199 			}
    200 		}
    201 #if VERBOSE > 4
    202 		output("Detach state was set sucessfully\n");
    203 #endif
    204 
    205 		/* Sched related attributes */
    206 		if (tps > 0) {	/* This routine is dependent on the Thread Execution Scheduling option */
    207 			if (scenarii[i].explicitsched == 1)
    208 				ret =
    209 				    pthread_attr_setinheritsched(&scenarii[i].
    210 								 ta,
    211 								 PTHREAD_EXPLICIT_SCHED);
    212 			else
    213 				ret =
    214 				    pthread_attr_setinheritsched(&scenarii[i].
    215 								 ta,
    216 								 PTHREAD_INHERIT_SCHED);
    217 			if (ret != 0) {
    218 				UNRESOLVED(ret,
    219 					   "Unable to set inheritsched attribute");
    220 			}
    221 #if VERBOSE > 4
    222 			output("inheritsched state was set sucessfully\n");
    223 #endif
    224 		}
    225 #if VERBOSE > 4
    226 		else
    227 			output
    228 			    ("TPS unsupported => inheritsched parameter untouched\n");
    229 #endif
    230 
    231 		if (tps > 0) {	/* This routine is dependent on the Thread Execution Scheduling option */
    232 			if (scenarii[i].schedpolicy == 1) {
    233 				ret =
    234 				    pthread_attr_setschedpolicy(&scenarii[i].ta,
    235 								SCHED_FIFO);
    236 			}
    237 			if (scenarii[i].schedpolicy == 2) {
    238 				ret =
    239 				    pthread_attr_setschedpolicy(&scenarii[i].ta,
    240 								SCHED_RR);
    241 			}
    242 			if (ret != 0) {
    243 				UNRESOLVED(ret,
    244 					   "Unable to set the sched policy");
    245 			}
    246 #if VERBOSE > 4
    247 			if (scenarii[i].schedpolicy)
    248 				output("Sched policy was set sucessfully\n");
    249 			else
    250 				output("Sched policy untouched\n");
    251 #endif
    252 		}
    253 #if VERBOSE > 4
    254 		else
    255 			output
    256 			    ("TPS unsupported => sched policy parameter untouched\n");
    257 #endif
    258 
    259 		if (scenarii[i].schedparam != 0) {
    260 			struct sched_param sp;
    261 
    262 			ret =
    263 			    pthread_attr_getschedpolicy(&scenarii[i].ta, &old);
    264 			if (ret != 0) {
    265 				UNRESOLVED(ret,
    266 					   "Unable to get sched policy from attribute");
    267 			}
    268 
    269 			if (scenarii[i].schedparam == 1)
    270 				sp.sched_priority = sched_get_priority_max(old);
    271 			if (scenarii[i].schedparam == -1)
    272 				sp.sched_priority = sched_get_priority_min(old);
    273 
    274 			ret = pthread_attr_setschedparam(&scenarii[i].ta, &sp);
    275 			if (ret != 0) {
    276 				UNRESOLVED(ret,
    277 					   "Failed to set the sched param");
    278 			}
    279 #if VERBOSE > 4
    280 			output("Sched param was set sucessfully to %i\n",
    281 			       sp.sched_priority);
    282 		} else {
    283 			output("Sched param untouched\n");
    284 #endif
    285 		}
    286 
    287 		if (tps > 0) {	/* This routine is dependent on the Thread Execution Scheduling option */
    288 			ret = pthread_attr_getscope(&scenarii[i].ta, &old);
    289 			if (ret != 0) {
    290 				UNRESOLVED(ret,
    291 					   "Failed to get contension scope from thread attribute");
    292 			}
    293 
    294 			if (scenarii[i].altscope != 0) {
    295 				if (old == PTHREAD_SCOPE_PROCESS)
    296 					old = PTHREAD_SCOPE_SYSTEM;
    297 				else
    298 					old = PTHREAD_SCOPE_PROCESS;
    299 
    300 				ret =
    301 				    pthread_attr_setscope(&scenarii[i].ta, old);
    302 				//if (ret != 0)  {  UNRESOLVED(ret, "Failed to set contension scope");  }
    303 #if VERBOSE > 0
    304 				if (ret != 0) {
    305 					output
    306 					    ("WARNING: The TPS option is claimed to be supported but setscope fails\n");
    307 				}
    308 #endif
    309 
    310 #if VERBOSE > 4
    311 				output("Contension scope set to %s\n",
    312 				       old ==
    313 				       PTHREAD_SCOPE_PROCESS ?
    314 				       "PTHREAD_SCOPE_PROCESS" :
    315 				       "PTHREAD_SCOPE_SYSTEM");
    316 			} else {
    317 				output("Contension scope untouched (%s)\n",
    318 				       old ==
    319 				       PTHREAD_SCOPE_PROCESS ?
    320 				       "PTHREAD_SCOPE_PROCESS" :
    321 				       "PTHREAD_SCOPE_SYSTEM");
    322 #endif
    323 			}
    324 		}
    325 #if VERBOSE > 4
    326 		else
    327 			output
    328 			    ("TPS unsupported => sched contension scope parameter untouched\n");
    329 #endif
    330 
    331 		/* Stack related attributes */
    332 		if ((tss > 0) && (tsa > 0)) {	/* This routine is dependent on the Thread Stack Address Attribute
    333 						   and Thread Stack Size Attribute options */
    334 			if (scenarii[i].altstack != 0) {
    335 				/* This is slightly more complicated. We need to alloc a new stack
    336 				   and free it upon test termination */
    337 				/* We will alloc with a simulated guardsize of 1 pagesize */
    338 				scenarii[i].bottom = malloc(minstacksize + pagesize);
    339 				if (scenarii[i].bottom == NULL) {
    340 					UNRESOLVED(errno,
    341 						   "Unable to alloc enough memory for alternative stack");
    342 				}
    343 
    344 				ret =
    345 				    pthread_attr_setstack(&scenarii[i].ta,
    346 							  scenarii[i].bottom,
    347 							  minstacksize);
    348 				if (ret != 0) {
    349 					UNRESOLVED(ret,
    350 						   "Failed to specify alternate stack");
    351 				}
    352 #if VERBOSE > 1
    353 				output
    354 				    ("Alternate stack created successfully. Bottom=%p, Size=%i\n",
    355 				     scenarii[i].bottom, minstacksize);
    356 #endif
    357 			}
    358 		}
    359 #if VERBOSE > 4
    360 		else
    361 			output
    362 			    ("TSA or TSS unsupported => No alternative stack\n");
    363 #endif
    364 
    365 #ifndef WITHOUT_XOPEN
    366 		if (scenarii[i].guard != 0) {
    367 			if (scenarii[i].guard == 1)
    368 				ret =
    369 				    pthread_attr_setguardsize(&scenarii[i].ta,
    370 							      0);
    371 			if (scenarii[i].guard == 2)
    372 				ret =
    373 				    pthread_attr_setguardsize(&scenarii[i].ta,
    374 							      pagesize);
    375 			if (ret != 0) {
    376 				UNRESOLVED(ret,
    377 					   "Unable to set guard area size in thread stack");
    378 			}
    379 #if VERBOSE > 4
    380 			output("Guard size set to %i\n",
    381 			       (scenarii[i].guard == 1) ? 1 : pagesize);
    382 #endif
    383 		}
    384 #endif
    385 
    386 		if (tss > 0) {	/* This routine is dependent on the Thread Stack Size Attribute option */
    387 			if (scenarii[i].altsize != 0) {
    388 				ret =
    389 				    pthread_attr_setstacksize(&scenarii[i].ta,
    390 							      minstacksize);
    391 				if (ret != 0) {
    392 					UNRESOLVED(ret,
    393 						   "Unable to change stack size");
    394 				}
    395 #if VERBOSE > 4
    396 				output
    397 				    ("Stack size set to %i (this is the min)\n",
    398 				     minstacksize);
    399 #endif
    400 			}
    401 		}
    402 #if VERBOSE > 4
    403 		else
    404 			output("TSS unsupported => stack size unchanged\n");
    405 #endif
    406 
    407 		ret = sem_init(&scenarii[i].sem, 0, 0);
    408 		if (ret == -1) {
    409 			UNRESOLVED(errno, "Unable to init a semaphore");
    410 		}
    411 
    412 	}
    413 #if VERBOSE > 0
    414 	output("All %i thread attribute objects were initialized\n\n", NSCENAR);
    415 #endif
    416 }
    417 
    418 /* This function will free all resources consumed in the scenar_init() routine */
    419 void scenar_fini(void)
    420 {
    421 	int ret = 0, i;
    422 
    423 	for (i = 0; i < NSCENAR; i++) {
    424 		if (scenarii[i].bottom != NULL)
    425 			free(scenarii[i].bottom);
    426 
    427 		ret = sem_destroy(&scenarii[i].sem);
    428 		if (ret == -1) {
    429 			UNRESOLVED(errno, "Unable to destroy a semaphore");
    430 		}
    431 
    432 		ret = pthread_attr_destroy(&scenarii[i].ta);
    433 		if (ret != 0) {
    434 			UNRESOLVED(ret,
    435 				   "Failed to destroy a thread attribute object");
    436 		}
    437 	}
    438 }
    439 
    440 int sc = 0;			/* This might be very dirty... but is much simpler */
    441 
    442 #ifdef STD_MAIN			/* We want main to be defined here */
    443 
    444 extern void *threaded(void *arg);	/* This is the test function */
    445 
    446 int main(int argc, char *argv[])
    447 {
    448 	int ret = 0;
    449 	pthread_t child;
    450 
    451 	/* Initialize output routine */
    452 	output_init();
    453 
    454 	/* Initialize thread attribute objects */
    455 	scenar_init();
    456 
    457 	for (sc = 0; sc < NSCENAR; sc++) {
    458 #if VERBOSE > 0
    459 		output("-----\n");
    460 		output("Starting test with scenario (%i): %s\n", sc,
    461 		       scenarii[sc].descr);
    462 #endif
    463 
    464 		ret = pthread_create(&child, &scenarii[sc].ta, threaded, NULL);
    465 		switch (scenarii[sc].result) {
    466 		case 0:	/* Operation was expected to succeed */
    467 			if (ret != 0) {
    468 				UNRESOLVED(ret, "Failed to create this thread");
    469 			}
    470 			break;
    471 
    472 		case 1:	/* Operation was expected to fail */
    473 			if (ret == 0) {
    474 				UNRESOLVED(-1,
    475 					   "An error was expected but the thread creation succeeded");
    476 			}
    477 			break;
    478 
    479 		case 2:	/* We did not know the expected result */
    480 		default:
    481 #if VERBOSE > 0
    482 			if (ret == 0) {
    483 				output
    484 				    ("Thread has been created successfully for this scenario\n");
    485 			} else {
    486 				output
    487 				    ("Thread creation failed with the error: %s\n",
    488 				     strerror(ret));
    489 			}
    490 #endif
    491 		}
    492 		if (ret == 0) {	/* The new thread is running */
    493 			if (scenarii[sc].detached == 0) {
    494 				ret = pthread_join(child, NULL);
    495 				if (ret != 0) {
    496 					UNRESOLVED(ret,
    497 						   "Unable to join a thread");
    498 				}
    499 			} else {
    500 				/* Just wait for the thread to terminate */
    501 				do {
    502 					ret = sem_wait(&scenarii[sc].sem);
    503 				}
    504 				while ((ret == -1) && (errno == EINTR));
    505 				if (ret == -1) {
    506 					UNRESOLVED(errno,
    507 						   "Failed to wait for the semaphore");
    508 				}
    509 			}
    510 		}
    511 	}
    512 
    513 	scenar_fini();
    514 #if VERBOSE > 0
    515 	output("-----\n");
    516 	output("All test data destroyed\n");
    517 	output("Test PASSED\n");
    518 #endif
    519 
    520 	PASSED;
    521 }
    522 #endif
    523