Home | History | Annotate | Download | only in pthread_cond_timedwait
      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 
    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 
    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 */
    628 int main(void)
    629 {
    630 	output_init();
    631 	UNTESTED("This test requires XSI features");
    632 }
    633 #endif
    634