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
28 struct __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 */
scenar_init()123 void 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 */
scenar_fini(void)338 void 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
355 int sc=0; /* This might be very dirty... but is much simpler */
356
357 #ifdef STD_MAIN /* We want main to be defined here */
358
359 extern void * threaded(void *arg); /* This is the test function */
360
main(int argc,char * argv[])361 int 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