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/* 1*/ ,CASE_POS( 1, 0, 0, 0, 0, 0, 0, 0, "detached") 82/* 2*/ ,CASE_POS( 0, 1, 0, 0, 0, 0, 0, 0, "Explicit sched") 83/* 3*/ ,CASE_UNK( 0, 0, 1, 0, 0, 0, 0, 0, "FIFO Policy") 84/* 4*/ ,CASE_UNK( 0, 0, 2, 0, 0, 0, 0, 0, "RR Policy") 85/* 5*/ ,CASE_UNK( 0, 0, 0, 1, 0, 0, 0, 0, "Max sched param") 86/* 6*/ ,CASE_UNK( 0, 0, 0,-1, 0, 0, 0, 0, "Min sched param") 87/* 7*/ ,CASE_POS( 0, 0, 0, 0, 1, 0, 0, 0, "Alternative contension scope") 88/* 8*/ ,CASE_POS( 0, 0, 0, 0, 0, 1, 0, 0, "Alternative stack") 89/* 9*/ ,CASE_POS( 0, 0, 0, 0, 0, 0, 1, 0, "No guard size") 90/*10*/ ,CASE_UNK( 0, 0, 0, 0, 0, 0, 2, 0, "1p guard size") 91/*11*/ ,CASE_POS( 0, 0, 0, 0, 0, 0, 0, 1, "Min stack size") 92 93 /* Stack play */ 94 ,CASE_POS( 0, 0, 0, 0, 0, 0, 1, 1, "Min stack size, no guard") 95 ,CASE_UNK( 0, 0, 0, 0, 0, 0, 2, 1, "Min stack size, 1p guard") 96 ,CASE_POS( 1, 0, 0, 0, 0, 1, 0, 0, "Detached, Alternative stack") 97 ,CASE_POS( 1, 0, 0, 0, 0, 0, 1, 1, "Detached, Min stack size, no guard") 98 ,CASE_UNK( 1, 0, 0, 0, 0, 0, 2, 1, "Detached, Min stack size, 1p guard") 99 100 /* Scheduling play -- all results are unknown since it might depend on the user priviledges */ 101 ,CASE_UNK( 0, 1, 1, 1, 0, 0, 0, 0, "Explicit FIFO max param") 102 ,CASE_UNK( 0, 1, 2, 1, 0, 0, 0, 0, "Explicit RR max param") 103 ,CASE_UNK( 0, 1, 1,-1, 0, 0, 0, 0, "Explicit FIFO min param") 104 ,CASE_UNK( 0, 1, 2,-1, 0, 0, 0, 0, "Explicit RR min param") 105 ,CASE_UNK( 0, 1, 1, 1, 1, 0, 0, 0, "Explicit FIFO max param, alt scope") 106 ,CASE_UNK( 0, 1, 2, 1, 1, 0, 0, 0, "Explicit RR max param, alt scope") 107 ,CASE_UNK( 0, 1, 1,-1, 1, 0, 0, 0, "Explicit FIFO min param, alt scope") 108 ,CASE_UNK( 0, 1, 2,-1, 1, 0, 0, 0, "Explicit RR min param, alt scope") 109 ,CASE_UNK( 1, 1, 1, 1, 0, 0, 0, 0, "Detached, explicit FIFO max param") 110 ,CASE_UNK( 1, 1, 2, 1, 0, 0, 0, 0, "Detached, explicit RR max param") 111 ,CASE_UNK( 1, 1, 1,-1, 0, 0, 0, 0, "Detached, explicit FIFO min param") 112 ,CASE_UNK( 1, 1, 2,-1, 0, 0, 0, 0, "Detached, explicit RR min param") 113 ,CASE_UNK( 1, 1, 1, 1, 1, 0, 0, 0, "Detached, explicit FIFO max param, alt scope") 114 ,CASE_UNK( 1, 1, 2, 1, 1, 0, 0, 0, "Detached, explicit RR max param, alt scope") 115 ,CASE_UNK( 1, 1, 1,-1, 1, 0, 0, 0, "Detached, explicit FIFO min param, alt scope") 116 ,CASE_UNK( 1, 1, 2,-1, 1, 0, 0, 0, "Detached, explicit RR min param, alt scope") 117 118}; 119 120#define NSCENAR (sizeof(scenarii) / sizeof(scenarii[0])) 121 122/* This function will initialize every pthread_attr_t object in the scenarii array */ 123void scenar_init() 124{ 125 int ret=0; 126 int i; 127 int old; 128 long pagesize, minstacksize; 129 long tsa, tss, tps; 130 131 pagesize =sysconf(_SC_PAGESIZE); 132 minstacksize =sysconf(_SC_THREAD_STACK_MIN); 133 tsa =sysconf(_SC_THREAD_ATTR_STACKADDR); 134 tss =sysconf(_SC_THREAD_ATTR_STACKSIZE); 135 tps =sysconf(_SC_THREAD_PRIORITY_SCHEDULING); 136 137 #if VERBOSE > 0 138 output("System abilities:\n"); 139 output(" TSA: %li\n", tsa); 140 output(" TSS: %li\n", tss); 141 output(" TPS: %li\n", tps); 142 output(" pagesize: %li\n", pagesize); 143 output(" min stack size: %li\n", minstacksize); 144 #endif 145 146 147 if (minstacksize % pagesize) 148 { 149 UNTESTED("The min stack size is not a multiple of the page size"); 150 } 151 152 for (i=0; i<NSCENAR; i++) 153 { 154 #if VERBOSE > 2 155 output("Initializing attribute for scenario %i: %s\n", i, scenarii[i].descr); 156 #endif 157 158 ret = pthread_attr_init(&scenarii[i].ta); 159 if (ret != 0) { UNRESOLVED(ret, "Failed to initialize a thread attribute object"); } 160 161 /* Set the attributes according to the scenario */ 162 if (scenarii[i].detached == 1) 163 { 164 ret = pthread_attr_setdetachstate(&scenarii[i].ta, PTHREAD_CREATE_DETACHED); 165 if (ret != 0) { UNRESOLVED(ret, "Unable to set detachstate"); } 166 } 167 else 168 { 169 ret = pthread_attr_getdetachstate(&scenarii[i].ta, &old); 170 if (ret != 0) { UNRESOLVED(ret, "Unable to get detachstate from initialized attribute"); } 171 if (old != PTHREAD_CREATE_JOINABLE) { FAILED("The default attribute is not PTHREAD_CREATE_JOINABLE"); } 172 } 173 #if VERBOSE > 4 174 output("Detach state was set sucessfully\n"); 175 #endif 176 177 /* Sched related attributes */ 178 if (tps>0) /* This routine is dependent on the Thread Execution Scheduling option */ 179 { 180 if (scenarii[i].explicitsched == 1) 181 ret = pthread_attr_setinheritsched(&scenarii[i].ta, PTHREAD_EXPLICIT_SCHED); 182 else 183 ret = pthread_attr_setinheritsched(&scenarii[i].ta, PTHREAD_INHERIT_SCHED); 184 if (ret != 0) { UNRESOLVED(ret, "Unable to set inheritsched attribute"); } 185 #if VERBOSE > 4 186 output("inheritsched state was set sucessfully\n"); 187 #endif 188 } 189 #if VERBOSE > 4 190 else 191 output("TPS unsupported => inheritsched parameter untouched\n"); 192 #endif 193 194 if (tps>0) /* This routine is dependent on the Thread Execution Scheduling option */ 195 { 196 if (scenarii[i].schedpolicy == 1) 197 { 198 ret = pthread_attr_setschedpolicy(&scenarii[i].ta, SCHED_FIFO); 199 } 200 if (scenarii[i].schedpolicy == 2) 201 { 202 ret = pthread_attr_setschedpolicy(&scenarii[i].ta, SCHED_RR); 203 } 204 if (ret != 0) { UNRESOLVED(ret, "Unable to set the sched policy"); } 205 #if VERBOSE > 4 206 if (scenarii[i].schedpolicy) 207 output("Sched policy was set sucessfully\n"); 208 else 209 output("Sched policy untouched\n"); 210 #endif 211 } 212 #if VERBOSE > 4 213 else 214 output("TPS unsupported => sched policy parameter untouched\n"); 215 #endif 216 217 if (scenarii[i].schedparam != 0) 218 { 219 struct sched_param sp; 220 221 ret = pthread_attr_getschedpolicy(&scenarii[i].ta, &old); 222 if (ret != 0) { UNRESOLVED(ret, "Unable to get sched policy from attribute"); } 223 224 if (scenarii[i].schedparam == 1) 225 sp.sched_priority = sched_get_priority_max(old); 226 if (scenarii[i].schedparam == -1) 227 sp.sched_priority = sched_get_priority_min(old); 228 229 ret = pthread_attr_setschedparam(&scenarii[i].ta, &sp); 230 if (ret != 0) { UNRESOLVED(ret, "Failed to set the sched param"); } 231 232 #if VERBOSE > 4 233 output("Sched param was set sucessfully to %i\n", sp.sched_priority); 234 } 235 else 236 { 237 output("Sched param untouched\n"); 238 #endif 239 } 240 241 if (tps>0) /* This routine is dependent on the Thread Execution Scheduling option */ 242 { 243 ret = pthread_attr_getscope(&scenarii[i].ta, &old); 244 if (ret != 0) { UNRESOLVED(ret, "Failed to get contension scope from thread attribute"); } 245 246 if (scenarii[i].altscope != 0) 247 { 248 if (old == PTHREAD_SCOPE_PROCESS) 249 old = PTHREAD_SCOPE_SYSTEM; 250 else 251 old = PTHREAD_SCOPE_PROCESS; 252 253 ret = pthread_attr_setscope(&scenarii[i].ta, old); 254 //if (ret != 0) { UNRESOLVED(ret, "Failed to set contension scope"); } 255 #if VERBOSE > 0 256 if (ret != 0) { output("WARNING: The TPS option is claimed to be supported but setscope fails\n"); } 257 #endif 258 259 #if VERBOSE > 4 260 output("Contension scope set to %s\n", old==PTHREAD_SCOPE_PROCESS?"PTHREAD_SCOPE_PROCESS":"PTHREAD_SCOPE_SYSTEM"); 261 } 262 else 263 { 264 output("Contension scope untouched (%s)\n", old==PTHREAD_SCOPE_PROCESS?"PTHREAD_SCOPE_PROCESS":"PTHREAD_SCOPE_SYSTEM"); 265 #endif 266 } 267 } 268 #if VERBOSE > 4 269 else 270 output("TPS unsupported => sched contension scope parameter untouched\n"); 271 #endif 272 273 /* Stack related attributes */ 274 if ((tss>0) && (tsa>0)) /* This routine is dependent on the Thread Stack Address Attribute 275 and Thread Stack Size Attribute options */ 276 { 277 if (scenarii[i].altstack != 0) 278 { 279 /* This is slightly more complicated. We need to alloc a new stack 280 and free it upon test termination */ 281 /* We will alloc with a simulated guardsize of 1 pagesize */ 282 scenarii[i].bottom = malloc(minstacksize + pagesize); 283 if (scenarii[i].bottom == NULL) { UNRESOLVED(errno,"Unable to alloc enough memory for alternative stack"); } 284 285 ret = pthread_attr_setstack(&scenarii[i].ta, scenarii[i].bottom, minstacksize); 286 if (ret != 0) { UNRESOLVED(ret, "Failed to specify alternate stack"); } 287 288 #if VERBOSE > 1 289 output("Alternate stack created successfully. Bottom=%p, Size=%i\n", scenarii[i].bottom, minstacksize); 290 #endif 291 } 292 } 293 #if VERBOSE > 4 294 else 295 output("TSA or TSS unsupported => No alternative stack\n"); 296 #endif 297 298 #ifndef WITHOUT_XOPEN 299 if (scenarii[i].guard != 0) 300 { 301 if (scenarii[i].guard == 1) 302 ret = pthread_attr_setguardsize(&scenarii[i].ta, 0); 303 if (scenarii[i].guard == 2) 304 ret = pthread_attr_setguardsize(&scenarii[i].ta, pagesize); 305 if (ret != 0) { UNRESOLVED(ret, "Unable to set guard area size in thread stack"); } 306 #if VERBOSE > 4 307 output("Guard size set to %i\n", (scenarii[i].guard==1)?1:pagesize); 308 #endif 309 } 310 #endif 311 312 if (tss>0) /* This routine is dependent on the Thread Stack Size Attribute option */ 313 { 314 if (scenarii[i].altsize != 0) 315 { 316 ret = pthread_attr_setstacksize(&scenarii[i].ta, minstacksize); 317 if (ret != 0) { UNRESOLVED(ret, "Unable to change stack size"); } 318 #if VERBOSE > 4 319 output("Stack size set to %i (this is the min)\n", minstacksize); 320 #endif 321 } 322 } 323 #if VERBOSE > 4 324 else 325 output("TSS unsupported => stack size unchanged\n"); 326 #endif 327 328 ret = sem_init(&scenarii[i].sem, 0,0); 329 if (ret == -1) { UNRESOLVED(errno, "Unable to init a semaphore"); } 330 331 } 332 #if VERBOSE > 0 333 output("All %i thread attribute objects were initialized\n\n", NSCENAR); 334 #endif 335} 336 337/* This function will free all resources consumed in the scenar_init() routine */ 338void scenar_fini(void) 339{ 340 int ret = 0, i; 341 342 for (i=0; i<NSCENAR; i++) 343 { 344 if (scenarii[i].bottom != NULL) 345 free(scenarii[i].bottom); 346 347 ret = sem_destroy(&scenarii[i].sem); 348 if (ret == -1) { UNRESOLVED(errno, "Unable to destroy a semaphore"); } 349 350 ret = pthread_attr_destroy(&scenarii[i].ta); 351 if (ret != 0) { UNRESOLVED(ret, "Failed to destroy a thread attribute object"); } 352 } 353} 354 355int sc=0; /* This might be very dirty... but is much simpler */ 356 357#ifdef STD_MAIN /* We want main to be defined here */ 358 359extern void * threaded(void *arg); /* This is the test function */ 360 361int main (int argc, char *argv[]) 362{ 363 int ret=0; 364 pthread_t child; 365 366 /* Initialize output routine */ 367 output_init(); 368 369 /* Initialize thread attribute objects */ 370 scenar_init(); 371 372 for (sc=0; sc < NSCENAR; sc++) 373 { 374 #if VERBOSE > 0 375 output("-----\n"); 376 output("Starting test with scenario (%i): %s\n", sc, scenarii[sc].descr); 377 #endif 378 379 ret = pthread_create(&child, &scenarii[sc].ta, threaded, NULL); 380 switch (scenarii[sc].result) 381 { 382 case 0: /* Operation was expected to succeed */ 383 if (ret != 0) { UNRESOLVED(ret, "Failed to create this thread"); } 384 break; 385 386 case 1: /* Operation was expected to fail */ 387 if (ret == 0) { UNRESOLVED(-1, "An error was expected but the thread creation succeeded"); } 388 break; 389 390 case 2: /* We did not know the expected result */ 391 default: 392 #if VERBOSE > 0 393 if (ret == 0) 394 { output("Thread has been created successfully for this scenario\n"); } 395 else 396 { output("Thread creation failed with the error: %s\n", strerror(ret)); } 397 #endif 398 } 399 if (ret == 0) /* The new thread is running */ 400 { 401 if (scenarii[sc].detached == 0) 402 { 403 ret = pthread_join(child, NULL); 404 if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); } 405 } 406 else 407 { 408 /* Just wait for the thread to terminate */ 409 do { ret = sem_wait(&scenarii[sc].sem); } 410 while ((ret == -1) && (errno == EINTR)); 411 if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); } 412 } 413 } 414 } 415 416 scenar_fini(); 417 #if VERBOSE > 0 418 output("-----\n"); 419 output("All test data destroyed\n"); 420 output("Test PASSED\n"); 421 #endif 422 423 PASSED; 424} 425#endif 426