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 26struct __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 */ 141void 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 */ 419void 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 440int sc = 0; /* This might be very dirty... but is much simpler */ 441 442#ifdef STD_MAIN /* We want main to be defined here */ 443 444extern void *threaded(void *arg); /* This is the test function */ 445 446int 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