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