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