/* * Copyright (c) 2004, Bull S.A.. All rights reserved. * Created by: Sebastien Decugis * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * This file is a helper file for the pthread_create tests * It defines the following objects: * scenarii: array of struct __scenario type. * NSCENAR : macro giving the total # of scenarii * scenar_init(): function to call before use the scenarii array. * scenar_fini(): function to call after end of use of the scenarii array. * */ struct __scenario { /* Object to hold the given configuration, and which will be used to create the threads */ pthread_attr_t ta; /* General parameters */ int detached; /* 0 => joinable; 1 => detached */ /* Scheduling parameters */ int explicitsched; /* 0 => sched policy is inherited; 1 => sched policy from the attr param */ int schedpolicy; /* 0 => default; 1=> SCHED_FIFO; 2=> SCHED_RR */ int schedparam; /* 0 => default sched param; 1 => max value for sched param; -1 => min value for sched param */ int altscope; /* 0 => default contension scope; 1 => alternative contension scope */ /* Stack parameters */ int altstack; /* 0 => system manages the stack; 1 => stack is provided */ int guard; /* 0 => default guardsize; 1=> guardsize is 0; 2=> guard is 1 page -- this setting only affect system stacks (not user's). */ int altsize; /* 0 => default stack size; 1 => stack size specified (min value) -- ignored when stack is provided */ /* Additionnal information */ char * descr; /* object description */ void * bottom; /* Stores the stack start when an alternate stack is required */ int result; /* This thread creation is expected to: 0 => succeed; 1 => fail; 2 => unknown */ sem_t sem; /* This semaphore is used to signal the end of the detached threads execution */ } scenarii[]= #define CASE(det,expl,scp,spa,sco,sta,gua,ssi,desc,res) \ { \ .detached=det, \ .explicitsched=expl, \ .schedpolicy=scp, \ .schedparam=spa, \ .altscope=sco, \ .altstack=sta, \ .guard=gua, \ .altsize=ssi, \ .descr=desc, \ .bottom=NULL, \ .result=res } #define CASE_POS(det,expl,scp,spa,sco,sta,gua,ssi,desc) CASE(det,expl,scp,spa,sco,sta,gua,ssi,desc,0) #define CASE_NEG(det,expl,scp,spa,sco,sta,gua,ssi,desc) CASE(det,expl,scp,spa,sco,sta,gua,ssi,desc,1) #define CASE_UNK(det,expl,scp,spa,sco,sta,gua,ssi,desc) CASE(det,expl,scp,spa,sco,sta,gua,ssi,desc,2) /* * This array gives the different combinations of threads attributes for the testcases. * * Some combinations must be avoided. * -> Do not have a detached thread use an alternative stack; * as we don't know when the thread terminates to free the stack memory * -> ... (to be completed) * */ { /* Unary tests */ /* 0*/ CASE_POS( 0, 0, 0, 0, 0, 0, 0, 0, "default") /* 1*/ ,CASE_POS( 1, 0, 0, 0, 0, 0, 0, 0, "detached") /* 2*/ ,CASE_POS( 0, 1, 0, 0, 0, 0, 0, 0, "Explicit sched") /* 3*/ ,CASE_UNK( 0, 0, 1, 0, 0, 0, 0, 0, "FIFO Policy") /* 4*/ ,CASE_UNK( 0, 0, 2, 0, 0, 0, 0, 0, "RR Policy") /* 5*/ ,CASE_UNK( 0, 0, 0, 1, 0, 0, 0, 0, "Max sched param") /* 6*/ ,CASE_UNK( 0, 0, 0,-1, 0, 0, 0, 0, "Min sched param") /* 7*/ ,CASE_POS( 0, 0, 0, 0, 1, 0, 0, 0, "Alternative contension scope") /* 8*/ ,CASE_POS( 0, 0, 0, 0, 0, 1, 0, 0, "Alternative stack") /* 9*/ ,CASE_POS( 0, 0, 0, 0, 0, 0, 1, 0, "No guard size") /*10*/ ,CASE_UNK( 0, 0, 0, 0, 0, 0, 2, 0, "1p guard size") /*11*/ ,CASE_POS( 0, 0, 0, 0, 0, 0, 0, 1, "Min stack size") /* Stack play */ ,CASE_POS( 0, 0, 0, 0, 0, 0, 1, 1, "Min stack size, no guard") ,CASE_UNK( 0, 0, 0, 0, 0, 0, 2, 1, "Min stack size, 1p guard") ,CASE_POS( 1, 0, 0, 0, 0, 1, 0, 0, "Detached, Alternative stack") ,CASE_POS( 1, 0, 0, 0, 0, 0, 1, 1, "Detached, Min stack size, no guard") ,CASE_UNK( 1, 0, 0, 0, 0, 0, 2, 1, "Detached, Min stack size, 1p guard") /* Scheduling play -- all results are unknown since it might depend on the user priviledges */ ,CASE_UNK( 0, 1, 1, 1, 0, 0, 0, 0, "Explicit FIFO max param") ,CASE_UNK( 0, 1, 2, 1, 0, 0, 0, 0, "Explicit RR max param") ,CASE_UNK( 0, 1, 1,-1, 0, 0, 0, 0, "Explicit FIFO min param") ,CASE_UNK( 0, 1, 2,-1, 0, 0, 0, 0, "Explicit RR min param") ,CASE_UNK( 0, 1, 1, 1, 1, 0, 0, 0, "Explicit FIFO max param, alt scope") ,CASE_UNK( 0, 1, 2, 1, 1, 0, 0, 0, "Explicit RR max param, alt scope") ,CASE_UNK( 0, 1, 1,-1, 1, 0, 0, 0, "Explicit FIFO min param, alt scope") ,CASE_UNK( 0, 1, 2,-1, 1, 0, 0, 0, "Explicit RR min param, alt scope") ,CASE_UNK( 1, 1, 1, 1, 0, 0, 0, 0, "Detached, explicit FIFO max param") ,CASE_UNK( 1, 1, 2, 1, 0, 0, 0, 0, "Detached, explicit RR max param") ,CASE_UNK( 1, 1, 1,-1, 0, 0, 0, 0, "Detached, explicit FIFO min param") ,CASE_UNK( 1, 1, 2,-1, 0, 0, 0, 0, "Detached, explicit RR min param") ,CASE_UNK( 1, 1, 1, 1, 1, 0, 0, 0, "Detached, explicit FIFO max param, alt scope") ,CASE_UNK( 1, 1, 2, 1, 1, 0, 0, 0, "Detached, explicit RR max param, alt scope") ,CASE_UNK( 1, 1, 1,-1, 1, 0, 0, 0, "Detached, explicit FIFO min param, alt scope") ,CASE_UNK( 1, 1, 2,-1, 1, 0, 0, 0, "Detached, explicit RR min param, alt scope") }; #define NSCENAR (sizeof(scenarii) / sizeof(scenarii[0])) /* This function will initialize every pthread_attr_t object in the scenarii array */ void scenar_init() { int ret=0; int i; int old; long pagesize, minstacksize; long tsa, tss, tps; pagesize =sysconf(_SC_PAGESIZE); minstacksize =sysconf(_SC_THREAD_STACK_MIN); tsa =sysconf(_SC_THREAD_ATTR_STACKADDR); tss =sysconf(_SC_THREAD_ATTR_STACKSIZE); tps =sysconf(_SC_THREAD_PRIORITY_SCHEDULING); #if VERBOSE > 0 output("System abilities:\n"); output(" TSA: %li\n", tsa); output(" TSS: %li\n", tss); output(" TPS: %li\n", tps); output(" pagesize: %li\n", pagesize); output(" min stack size: %li\n", minstacksize); #endif if (minstacksize % pagesize) { UNTESTED("The min stack size is not a multiple of the page size"); } for (i=0; i 2 output("Initializing attribute for scenario %i: %s\n", i, scenarii[i].descr); #endif ret = pthread_attr_init(&scenarii[i].ta); if (ret != 0) { UNRESOLVED(ret, "Failed to initialize a thread attribute object"); } /* Set the attributes according to the scenario */ if (scenarii[i].detached == 1) { ret = pthread_attr_setdetachstate(&scenarii[i].ta, PTHREAD_CREATE_DETACHED); if (ret != 0) { UNRESOLVED(ret, "Unable to set detachstate"); } } else { ret = pthread_attr_getdetachstate(&scenarii[i].ta, &old); if (ret != 0) { UNRESOLVED(ret, "Unable to get detachstate from initialized attribute"); } if (old != PTHREAD_CREATE_JOINABLE) { FAILED("The default attribute is not PTHREAD_CREATE_JOINABLE"); } } #if VERBOSE > 4 output("Detach state was set sucessfully\n"); #endif /* Sched related attributes */ if (tps>0) /* This routine is dependent on the Thread Execution Scheduling option */ { if (scenarii[i].explicitsched == 1) ret = pthread_attr_setinheritsched(&scenarii[i].ta, PTHREAD_EXPLICIT_SCHED); else ret = pthread_attr_setinheritsched(&scenarii[i].ta, PTHREAD_INHERIT_SCHED); if (ret != 0) { UNRESOLVED(ret, "Unable to set inheritsched attribute"); } #if VERBOSE > 4 output("inheritsched state was set sucessfully\n"); #endif } #if VERBOSE > 4 else output("TPS unsupported => inheritsched parameter untouched\n"); #endif if (tps>0) /* This routine is dependent on the Thread Execution Scheduling option */ { if (scenarii[i].schedpolicy == 1) { ret = pthread_attr_setschedpolicy(&scenarii[i].ta, SCHED_FIFO); } if (scenarii[i].schedpolicy == 2) { ret = pthread_attr_setschedpolicy(&scenarii[i].ta, SCHED_RR); } if (ret != 0) { UNRESOLVED(ret, "Unable to set the sched policy"); } #if VERBOSE > 4 if (scenarii[i].schedpolicy) output("Sched policy was set sucessfully\n"); else output("Sched policy untouched\n"); #endif } #if VERBOSE > 4 else output("TPS unsupported => sched policy parameter untouched\n"); #endif if (scenarii[i].schedparam != 0) { struct sched_param sp; ret = pthread_attr_getschedpolicy(&scenarii[i].ta, &old); if (ret != 0) { UNRESOLVED(ret, "Unable to get sched policy from attribute"); } if (scenarii[i].schedparam == 1) sp.sched_priority = sched_get_priority_max(old); if (scenarii[i].schedparam == -1) sp.sched_priority = sched_get_priority_min(old); ret = pthread_attr_setschedparam(&scenarii[i].ta, &sp); if (ret != 0) { UNRESOLVED(ret, "Failed to set the sched param"); } #if VERBOSE > 4 output("Sched param was set sucessfully to %i\n", sp.sched_priority); } else { output("Sched param untouched\n"); #endif } if (tps>0) /* This routine is dependent on the Thread Execution Scheduling option */ { ret = pthread_attr_getscope(&scenarii[i].ta, &old); if (ret != 0) { UNRESOLVED(ret, "Failed to get contension scope from thread attribute"); } if (scenarii[i].altscope != 0) { if (old == PTHREAD_SCOPE_PROCESS) old = PTHREAD_SCOPE_SYSTEM; else old = PTHREAD_SCOPE_PROCESS; ret = pthread_attr_setscope(&scenarii[i].ta, old); //if (ret != 0) { UNRESOLVED(ret, "Failed to set contension scope"); } #if VERBOSE > 0 if (ret != 0) { output("WARNING: The TPS option is claimed to be supported but setscope fails\n"); } #endif #if VERBOSE > 4 output("Contension scope set to %s\n", old==PTHREAD_SCOPE_PROCESS?"PTHREAD_SCOPE_PROCESS":"PTHREAD_SCOPE_SYSTEM"); } else { output("Contension scope untouched (%s)\n", old==PTHREAD_SCOPE_PROCESS?"PTHREAD_SCOPE_PROCESS":"PTHREAD_SCOPE_SYSTEM"); #endif } } #if VERBOSE > 4 else output("TPS unsupported => sched contension scope parameter untouched\n"); #endif /* Stack related attributes */ if ((tss>0) && (tsa>0)) /* This routine is dependent on the Thread Stack Address Attribute and Thread Stack Size Attribute options */ { if (scenarii[i].altstack != 0) { /* This is slightly more complicated. We need to alloc a new stack and free it upon test termination */ /* We will alloc with a simulated guardsize of 1 pagesize */ scenarii[i].bottom = malloc(minstacksize + pagesize); if (scenarii[i].bottom == NULL) { UNRESOLVED(errno,"Unable to alloc enough memory for alternative stack"); } ret = pthread_attr_setstack(&scenarii[i].ta, scenarii[i].bottom, minstacksize); if (ret != 0) { UNRESOLVED(ret, "Failed to specify alternate stack"); } #if VERBOSE > 1 output("Alternate stack created successfully. Bottom=%p, Size=%i\n", scenarii[i].bottom, minstacksize); #endif } } #if VERBOSE > 4 else output("TSA or TSS unsupported => No alternative stack\n"); #endif #ifndef WITHOUT_XOPEN if (scenarii[i].guard != 0) { if (scenarii[i].guard == 1) ret = pthread_attr_setguardsize(&scenarii[i].ta, 0); if (scenarii[i].guard == 2) ret = pthread_attr_setguardsize(&scenarii[i].ta, pagesize); if (ret != 0) { UNRESOLVED(ret, "Unable to set guard area size in thread stack"); } #if VERBOSE > 4 output("Guard size set to %i\n", (scenarii[i].guard==1)?1:pagesize); #endif } #endif if (tss>0) /* This routine is dependent on the Thread Stack Size Attribute option */ { if (scenarii[i].altsize != 0) { ret = pthread_attr_setstacksize(&scenarii[i].ta, minstacksize); if (ret != 0) { UNRESOLVED(ret, "Unable to change stack size"); } #if VERBOSE > 4 output("Stack size set to %i (this is the min)\n", minstacksize); #endif } } #if VERBOSE > 4 else output("TSS unsupported => stack size unchanged\n"); #endif ret = sem_init(&scenarii[i].sem, 0,0); if (ret == -1) { UNRESOLVED(errno, "Unable to init a semaphore"); } } #if VERBOSE > 0 output("All %i thread attribute objects were initialized\n\n", NSCENAR); #endif } /* This function will free all resources consumed in the scenar_init() routine */ void scenar_fini(void) { int ret = 0, i; for (i=0; i 0 output("-----\n"); output("Starting test with scenario (%i): %s\n", sc, scenarii[sc].descr); #endif ret = pthread_create(&child, &scenarii[sc].ta, threaded, NULL); switch (scenarii[sc].result) { case 0: /* Operation was expected to succeed */ if (ret != 0) { UNRESOLVED(ret, "Failed to create this thread"); } break; case 1: /* Operation was expected to fail */ if (ret == 0) { UNRESOLVED(-1, "An error was expected but the thread creation succeeded"); } break; case 2: /* We did not know the expected result */ default: #if VERBOSE > 0 if (ret == 0) { output("Thread has been created successfully for this scenario\n"); } else { output("Thread creation failed with the error: %s\n", strerror(ret)); } #endif } if (ret == 0) /* The new thread is running */ { if (scenarii[sc].detached == 0) { ret = pthread_join(child, NULL); if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); } } else { /* Just wait for the thread to terminate */ do { ret = sem_wait(&scenarii[sc].sem); } while ((ret == -1) && (errno == EINTR)); if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); } } } } scenar_fini(); #if VERBOSE > 0 output("-----\n"); output("All test data destroyed\n"); output("Test PASSED\n"); #endif PASSED; } #endif