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 sample test aims to check the following assertion:
18 *
19 * When the abstime parameter is invalid,
20 * the function must return EINVAL and
21 * the mutex state must not have changed during the call.
22
23 * The steps are:
24 * -> parent (for each mutex type and each condvar options, across threads or processes)
25 * -> locks the mutex m
26 * -> sets ctrl = 0
27 * -> creates a bunch of children, which:
28 * -> lock the mutex m
29 * -> if ctrl == 0, test has failed
30 * -> unlock the mutex then exit
31 * -> calls pthread_cond_timedwait with invalid values (nsec > 999999999)
32 * -> sets ctrl = non-zero value
33 * -> unlocks the mutex m
34 */
35
36 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
37 #define _POSIX_C_SOURCE 200112L
38
39 /* We need the XSI extention for the mutex attributes
40 and the mkstemp() routine */
41 #ifndef WITHOUT_XOPEN
42 #define _XOPEN_SOURCE 600
43 #endif
44
45 #include <pthread.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50
51 #include <errno.h>
52 #include <sys/wait.h>
53 #include <sys/mman.h>
54 #include <string.h>
55 #include <time.h>
56
57 #include "../testfrmw/testfrmw.h"
58 #include "../testfrmw/testfrmw.c"
59
60 #ifndef VERBOSE
61 #define VERBOSE 1
62 #endif
63
64 #define NCHILDREN (20)
65
66 #ifndef WITHOUT_ALTCLK
67 #define USE_ALTCLK /* make tests with MONOTONIC CLOCK if supported */
68 #endif
69
70 #ifndef WITHOUT_XOPEN
71
72 typedef struct {
73 pthread_mutex_t mtx;
74 int ctrl; /* Control value */
75 int gotit; /* Thread locked the mutex while ctrl == 0 */
76 int status; /* error code */
77 } testdata_t;
78
79 struct _scenar {
80 int m_type; /* Mutex type to use */
81 int mc_pshared; /* 0: mutex and cond are process-private (default) ~ !0: Both are process-shared, if supported */
82 int c_clock; /* 0: cond uses the default clock. ~ !0: Cond uses monotonic clock, if supported. */
83 int fork; /* 0: Test between threads. ~ !0: Test across processes, if supported (mmap) */
84 char *descr; /* Case description */
85 } scenarii[] = {
86 {
87 PTHREAD_MUTEX_DEFAULT, 0, 0, 0, "Default mutex"}
88 , {
89 PTHREAD_MUTEX_NORMAL, 0, 0, 0, "Normal mutex"}
90 , {
91 PTHREAD_MUTEX_ERRORCHECK, 0, 0, 0, "Errorcheck mutex"}
92 , {
93 PTHREAD_MUTEX_RECURSIVE, 0, 0, 0, "Recursive mutex"}
94
95 , {
96 PTHREAD_MUTEX_DEFAULT, 1, 0, 0, "PShared default mutex"}
97 , {
98 PTHREAD_MUTEX_NORMAL, 1, 0, 0, "Pshared normal mutex"}
99 , {
100 PTHREAD_MUTEX_ERRORCHECK, 1, 0, 0, "Pshared errorcheck mutex"}
101 , {
102 PTHREAD_MUTEX_RECURSIVE, 1, 0, 0, "Pshared recursive mutex"}
103
104 , {
105 PTHREAD_MUTEX_DEFAULT, 1, 0, 1,
106 "Pshared default mutex across processes"}
107 , {
108 PTHREAD_MUTEX_NORMAL, 1, 0, 1,
109 "Pshared normal mutex across processes"}
110 , {
111 PTHREAD_MUTEX_ERRORCHECK, 1, 0, 1,
112 "Pshared errorcheck mutex across processes"}
113 , {
114 PTHREAD_MUTEX_RECURSIVE, 1, 0, 1,
115 "Pshared recursive mutex across processes"}
116
117 #ifdef USE_ALTCLK
118 , {
119 PTHREAD_MUTEX_DEFAULT, 1, 1, 1,
120 "Pshared default mutex and alt clock condvar across processes"}
121 , {
122 PTHREAD_MUTEX_NORMAL, 1, 1, 1,
123 "Pshared normal mutex and alt clock condvar across processes"}
124 , {
125 PTHREAD_MUTEX_ERRORCHECK, 1, 1, 1,
126 "Pshared errorcheck mutex and alt clock condvar across processes"}
127 , {
128 PTHREAD_MUTEX_RECURSIVE, 1, 1, 1,
129 "Pshared recursive mutex and alt clock condvar across processes"}
130
131 , {
132 PTHREAD_MUTEX_DEFAULT, 0, 1, 0,
133 "Default mutex and alt clock condvar"}
134 , {
135 PTHREAD_MUTEX_NORMAL, 0, 1, 0,
136 "Normal mutex and alt clock condvar"}
137 , {
138 PTHREAD_MUTEX_ERRORCHECK, 0, 1, 0,
139 "Errorcheck mutex and alt clock condvar"}
140 , {
141 PTHREAD_MUTEX_RECURSIVE, 0, 1, 0,
142 "Recursive mutex and alt clock condvar"}
143
144 , {
145 PTHREAD_MUTEX_DEFAULT, 1, 1, 0,
146 "PShared default mutex and alt clock condvar"}
147 , {
148 PTHREAD_MUTEX_NORMAL, 1, 1, 0,
149 "Pshared normal mutex and alt clock condvar"}
150 , {
151 PTHREAD_MUTEX_ERRORCHECK, 1, 1, 0,
152 "Pshared errorcheck mutex and alt clock condvar"}
153 , {
154 PTHREAD_MUTEX_RECURSIVE, 1, 1, 0,
155 "Pshared recursive mutex and alt clock condvar"}
156 #endif
157 };
158
159 struct {
160 long sec_val; /* Value for seconds */
161 short sec_is_offset; /* Seconds value is added to current time or is absolute */
162 long nsec_val; /* Value for nanoseconds */
163 short nsec_is_offset; /* Nanoseconds value is added to current time or is absolute */
164 } junks_ts[] = {
165 {
166 -2, 1, 1000000000, 1}
167 , {
168 -2, 1, -1, 0}
169 , {
170 -3, 1, 2000000000, 0}
171 };
172
tf(void * arg)173 void *tf(void *arg)
174 {
175 int ret = 0;
176
177 testdata_t *td = (testdata_t *) arg;
178
179 /* Lock the mutex */
180 ret = pthread_mutex_lock(&(td->mtx));
181 if (ret != 0) {
182 td->status = ret;
183 UNRESOLVED(ret, "[child] Unable to lock the mutex");
184 }
185
186 /* Checks whether the parent release the lock inside the timedwait function */
187 if (td->ctrl == 0)
188 td->gotit += 1;
189
190 /* Unlock and exit */
191 ret = pthread_mutex_unlock(&(td->mtx));
192 if (ret != 0) {
193 td->status = ret;
194 UNRESOLVED(ret, "[child] Failed to unlock the mutex.");
195 }
196 return NULL;
197 }
198
main(void)199 int main(void)
200 {
201 int ret, k;
202 unsigned int i, j;
203 pthread_mutexattr_t ma;
204 pthread_condattr_t ca;
205 pthread_cond_t cnd;
206 clockid_t cid = CLOCK_REALTIME;
207 struct timespec ts, ts_junk;
208
209 testdata_t *td;
210 testdata_t alternativ;
211
212 int do_fork;
213
214 pid_t child_pr[NCHILDREN], chkpid;
215 int status;
216 pthread_t child_th[NCHILDREN];
217
218 long pshared, monotonic, cs, mf;
219
220 output_init();
221 pshared = sysconf(_SC_THREAD_PROCESS_SHARED);
222 cs = sysconf(_SC_CLOCK_SELECTION);
223 monotonic = sysconf(_SC_MONOTONIC_CLOCK);
224 mf = sysconf(_SC_MAPPED_FILES);
225
226 #if VERBOSE > 0
227 output("Test starting\n");
228 output("System abilities:\n");
229 output(" TPS : %li\n", pshared);
230 output(" CS : %li\n", cs);
231 output(" MON : %li\n", monotonic);
232 output(" MF : %li\n", mf);
233 if ((mf < 0) || (pshared < 0))
234 output("Process-shared attributes won't be tested\n");
235 if ((cs < 0) || (monotonic < 0))
236 output("Alternative clock won't be tested\n");
237 fflush(stdout);
238 #endif
239
240 /* We are not interested in testing the clock if we have no other clock available.. */
241 if (monotonic < 0)
242 cs = -1;
243
244 #ifndef USE_ALTCLK
245 if (cs > 0)
246 output
247 ("Implementation supports the MONOTONIC CLOCK but option is disabled in test.\n");
248 #endif
249
250 /**********
251 * Allocate space for the testdata structure
252 */
253 if (mf < 0) {
254 /* Cannot mmap a file, we use an alternative method */
255 td = &alternativ;
256 pshared = -1; /* We won't do this testing anyway */
257 #if VERBOSE > 0
258 output("Testdata allocated in the process memory.\n");
259 #endif
260 } else {
261 /* We will place the test data in a mmaped file */
262 char filename[] = "/tmp/cond_timedwait_2-4-XXXXXX";
263 size_t sz;
264 void *mmaped;
265 int fd;
266 char *tmp;
267
268 /* We now create the temp files */
269 fd = mkstemp(filename);
270 if (fd == -1) {
271 UNRESOLVED(errno,
272 "Temporary file could not be created");
273 }
274
275 /* and make sure the file will be deleted when closed */
276 unlink(filename);
277
278 #if VERBOSE > 1
279 output("Temp file created (%s).\n", filename);
280 #endif
281
282 sz = (size_t) sysconf(_SC_PAGESIZE);
283
284 tmp = calloc(1, sz);
285 if (tmp == NULL) {
286 UNRESOLVED(errno, "Memory allocation failed");
287 }
288
289 /* Write the data to the file. */
290 if (write(fd, tmp, sz) != (ssize_t) sz) {
291 UNRESOLVED(sz, "Writting to the file failed");
292 }
293
294 free(tmp);
295
296 /* Now we can map the file in memory */
297 mmaped =
298 mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
299 if (mmaped == MAP_FAILED) {
300 UNRESOLVED(errno, "mmap failed");
301 }
302
303 td = (testdata_t *) mmaped;
304
305 /* Our datatest structure is now in shared memory */
306 #if VERBOSE > 1
307 output("Testdata allocated in shared memory.\n");
308 #endif
309 }
310
311 /**********
312 * For each test scenario, initialize the attributes and other variables.
313 * Do the whole thing for each time to test.
314 */
315 for (i = 0; i < (sizeof(scenarii) / sizeof(scenarii[0])); i++) {
316 for (j = 0; j < (sizeof(junks_ts) / sizeof(junks_ts[0])); j++) {
317 #if VERBOSE > 1
318 output("[parent] Preparing attributes for: %s\n",
319 scenarii[i].descr);
320 #endif
321 /* set / reset everything */
322 do_fork = 0;
323 ret = pthread_mutexattr_init(&ma);
324 if (ret != 0) {
325 UNRESOLVED(ret,
326 "[parent] Unable to initialize the mutex attribute object");
327 }
328 ret = pthread_condattr_init(&ca);
329 if (ret != 0) {
330 UNRESOLVED(ret,
331 "[parent] Unable to initialize the cond attribute object");
332 }
333
334 /* Set the mutex type */
335 ret =
336 pthread_mutexattr_settype(&ma, scenarii[i].m_type);
337 if (ret != 0) {
338 UNRESOLVED(ret,
339 "[parent] Unable to set mutex type");
340 }
341 #if VERBOSE > 1
342 output("[parent] Mutex type : %i\n",
343 scenarii[i].m_type);
344 #endif
345
346 /* Set the pshared attributes, if supported */
347 if ((pshared > 0) && (scenarii[i].mc_pshared != 0)) {
348 ret =
349 pthread_mutexattr_setpshared(&ma,
350 PTHREAD_PROCESS_SHARED);
351 if (ret != 0) {
352 UNRESOLVED(ret,
353 "[parent] Unable to set the mutex process-shared");
354 }
355 ret =
356 pthread_condattr_setpshared(&ca,
357 PTHREAD_PROCESS_SHARED);
358 if (ret != 0) {
359 UNRESOLVED(ret,
360 "[parent] Unable to set the cond var process-shared");
361 }
362 #if VERBOSE > 1
363 output
364 ("[parent] Mutex & cond are process-shared\n");
365 #endif
366 }
367 #if VERBOSE > 1
368 else {
369 output
370 ("[parent] Mutex & cond are process-private\n");
371 }
372 #endif
373
374 /* Set the alternative clock, if supported */
375 #ifdef USE_ALTCLK
376 if ((cs > 0) && (scenarii[i].c_clock != 0)) {
377 ret =
378 pthread_condattr_setclock(&ca,
379 CLOCK_MONOTONIC);
380 if (ret != 0) {
381 UNRESOLVED(ret,
382 "[parent] Unable to set the monotonic clock for the cond");
383 }
384 #if VERBOSE > 1
385 output
386 ("[parent] Cond uses the Monotonic clock\n");
387 #endif
388 }
389 #if VERBOSE > 1
390 else {
391 output
392 ("[parent] Cond uses the default clock\n");
393 }
394 #endif
395 ret = pthread_condattr_getclock(&ca, &cid);
396 if (ret != 0) {
397 UNRESOLVED(ret,
398 "Unable to get clock from cond attr");
399 }
400 #endif
401
402 /* Tell whether the test will be across processes */
403 if ((pshared > 0) && (scenarii[i].fork != 0)) {
404 do_fork = 1;
405 #if VERBOSE > 1
406 output
407 ("[parent] Child will be a new process\n");
408 #endif
409 }
410 #if VERBOSE > 1
411 else {
412 output("[parent] Child will be a new thread\n");
413 }
414 #endif
415
416 /* initialize the condvar */
417 ret = pthread_cond_init(&cnd, &ca);
418 if (ret != 0) {
419 UNRESOLVED(ret, "[parent] Cond init failed");
420 }
421
422 /**********
423 * Initialize the testdata_t structure with the previously defined attributes
424 */
425 /* Initialize the mutex */
426 ret = pthread_mutex_init(&(td->mtx), &ma);
427 if (ret != 0) {
428 UNRESOLVED(ret, "[parent] Mutex init failed");
429 }
430
431 /* Initialize the other datas from the test structure */
432 td->ctrl = 0;
433 td->gotit = 0;
434 td->status = 0;
435
436 /**********
437 * Proceed to the actual testing
438 */
439 /* Lock the mutex before creating children */
440 ret = pthread_mutex_lock(&(td->mtx));
441 if (ret != 0) {
442 UNRESOLVED(ret,
443 "[parent] Unable to lock the mutex");
444 }
445
446 /* Create the children */
447 if (do_fork != 0) {
448 /* We are testing across processes */
449 for (k = 0; k < NCHILDREN; k++) {
450 child_pr[k] = fork();
451 if (child_pr[k] == -1) {
452 UNRESOLVED(errno,
453 "[parent] Fork failed");
454 }
455
456 if (child_pr[k] == 0) {
457 #if VERBOSE > 3
458 output
459 ("[child] Child process %i starting...\n",
460 k);
461 #endif
462
463 if (tf((void *)td) != NULL) {
464 UNRESOLVED(-1,
465 "[child] Got an unexpected return value from test function");
466 } else {
467 /* We cannot use the PASSED macro here since it would terminate the output */
468 exit(0);
469 }
470 }
471 }
472 /* Only the parent process goes further */
473 } else { /* do_fork == 0 */
474
475 /* We are testing across two threads */
476 for (k = 0; k < NCHILDREN; k++) {
477 ret =
478 pthread_create(&child_th[k], NULL,
479 tf, td);
480 if (ret != 0) {
481 UNRESOLVED(ret,
482 "[parent] Unable to create the child thread.");
483 }
484 }
485 }
486
487 /* Children are now running and trying to lock the mutex. */
488
489 ret = clock_gettime(cid, &ts);
490 if (ret != 0) {
491 UNRESOLVED(ret,
492 "[parent] Unable to read clock");
493 }
494
495 /* Do the junk timedwaits */
496 ts_junk.tv_sec =
497 junks_ts[j].sec_val +
498 (junks_ts[j].sec_is_offset ? ts.tv_sec : 0);
499 ts_junk.tv_nsec =
500 junks_ts[j].nsec_val +
501 (junks_ts[j].nsec_is_offset ? ts.tv_nsec : 0);
502
503 #if VERBOSE > 2
504 output("TS: s = %s%li ; ns = %s%li\n",
505 junks_ts[j].sec_is_offset ? "n + " : " ",
506 junks_ts[j].sec_val,
507 junks_ts[j].nsec_is_offset ? "n + " : " ",
508 junks_ts[j].nsec_val);
509 output("Now is: %i.%09li\n", ts.tv_sec, ts.tv_nsec);
510 output("Junk is: %i.%09li\n", ts_junk.tv_sec,
511 ts_junk.tv_nsec);
512 #endif
513
514 do {
515 ret =
516 pthread_cond_timedwait(&cnd, &(td->mtx),
517 &ts_junk);
518 } while (ret == 0);
519 #if VERBOSE > 2
520 output("timedwait returns %d (%s) - gotit = %d\n", ret,
521 strerror(ret), td->gotit);
522 #endif
523
524 /* check that when EINVAL is returned, the mutex has not been released */
525 if (ret == EINVAL) {
526 if (td->gotit != 0) {
527 FAILED
528 ("The mutex was released when an invalid timestamp was detected in the function");
529 }
530 #if VERBOSE > 0
531 } else {
532 output
533 ("Warning, struct timespec with tv_sec = %i and tv_nsec = %li was not invalid\n",
534 ts_junk.tv_sec, ts_junk.tv_nsec);
535 }
536 #endif
537
538 /* Finally unlock the mutex */
539 td->ctrl = 1;
540 ret = pthread_mutex_unlock(&(td->mtx));
541 if (ret != 0) {
542 UNRESOLVED(ret,
543 "[parent] Unable to unlock the mutex");
544 }
545
546 /* Wait for the child to terminate */
547 if (do_fork != 0) {
548 /* We were testing across processes */
549 ret = 0;
550 for (k = 0; k < NCHILDREN; k++) {
551 chkpid =
552 waitpid(child_pr[k], &status, 0);
553 if (chkpid != child_pr[k]) {
554 output
555 ("Expected pid: %i. Got %i\n",
556 (int)child_pr[k],
557 (int)chkpid);
558 UNRESOLVED(errno,
559 "Waitpid failed");
560 }
561 if (WIFSIGNALED(status)) {
562 output
563 ("Child process killed with signal %d\n",
564 WTERMSIG(status));
565 UNRESOLVED(-1,
566 "Child process was killed");
567 }
568
569 if (WIFEXITED(status)) {
570 ret |= WEXITSTATUS(status);
571 } else {
572 UNRESOLVED(-1,
573 "Child process was neither killed nor exited");
574 }
575 }
576 if (ret != 0) {
577 exit(ret); /* Output has already been closed in child */
578 }
579
580 } else { /* child was a thread */
581
582 for (k = 0; k < NCHILDREN; k++) {
583 ret = pthread_join(child_th[k], NULL);
584 if (ret != 0) {
585 UNRESOLVED(ret,
586 "[parent] Unable to join the thread");
587 }
588 }
589 }
590
591 /**********
592 * Destroy the data
593 */
594 ret = pthread_cond_destroy(&cnd);
595 if (ret != 0) {
596 UNRESOLVED(ret,
597 "Failed to destroy the cond var");
598 }
599
600 ret = pthread_mutex_destroy(&(td->mtx));
601 if (ret != 0) {
602 UNRESOLVED(ret, "Failed to destroy the mutex");
603 }
604
605 ret = pthread_condattr_destroy(&ca);
606 if (ret != 0) {
607 UNRESOLVED(ret,
608 "Failed to destroy the cond var attribute object");
609 }
610
611 ret = pthread_mutexattr_destroy(&ma);
612 if (ret != 0) {
613 UNRESOLVED(ret,
614 "Failed to destroy the mutex attribute object");
615 }
616
617 } /* Proceed to the next junk timedwait value */
618 } /* Proceed to the next scenario */
619
620 #if VERBOSE > 0
621 output("Test passed\n");
622 #endif
623
624 PASSED;
625 }
626
627 #else /* WITHOUT_XOPEN */
main(void)628 int main(void)
629 {
630 output_init();
631 UNTESTED("This test requires XSI features");
632 }
633 #endif
634