• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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