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 25struct __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 */ 145CASE_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 */ 194void 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 */ 465void 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 485unsigned int sc; 486 487#ifdef STD_MAIN 488 489extern void *threaded(void *arg); 490 491int 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