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