• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
scenar_init(void)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  */
scenar_fini(void)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 
main(void)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