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  * This function is a cancelation point: when cancelability
     20  * is PTHREAD_CANCEL_DEFERRED and a cancel request falls, the thread
     21  * must relock the mutex before the first (if any) clean up handler is called.
     22 
     23  * The steps are:
     24  * -> Create a thread
     25  *   ->  this thread locks a mutex then waits for a condition
     26  * -> cancel the thread
     27  *   -> the cancelation handler will test if the thread owns the mutex.
     28  */
     29 
     30  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
     31 #define _POSIX_C_SOURCE 200112L
     32 
     33  /* We need the XSI extention for the mutex attributes */
     34 #ifndef WITHOUT_XOPEN
     35 #define _XOPEN_SOURCE	600
     36 #endif
     37 
     38 #include <pthread.h>
     39 #include <stdarg.h>
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <unistd.h>
     43 
     44 #include <errno.h>
     45 #include <time.h>
     46 #include <semaphore.h>
     47 
     48 #include "../testfrmw/testfrmw.h"
     49 #include "../testfrmw/testfrmw.c"
     50 
     51 #ifndef VERBOSE
     52 #define VERBOSE 1
     53 #endif
     54 
     55 #ifndef WITHOUT_ALTCLK
     56 #define USE_ALTCLK		/* make tests with MONOTONIC CLOCK if supported */
     57 #endif
     58 
     59 struct {
     60 	pthread_mutex_t mtx;
     61 	pthread_cond_t cnd;
     62 	int type;
     63 	clockid_t cid;
     64 	sem_t semA;
     65 	sem_t semB;
     66 	int bool;
     67 } data;
     68 
     69 /****  First handler that will be poped
     70  *  This one works only with recursive mutexes
     71  */
     72 void clnp1(void *arg)
     73 {
     74 	int ret;
     75 
     76 	(void) arg;
     77 
     78 	if (data.type == PTHREAD_MUTEX_RECURSIVE) {
     79 		ret = pthread_mutex_trylock(&(data.mtx));
     80 		if (ret != 0) {
     81 			FAILED
     82 			    ("Unable to double-lock a recursive mutex in clean-up handler 1");
     83 		}
     84 		ret = pthread_mutex_unlock(&(data.mtx));
     85 		if (ret != 0) {
     86 			UNRESOLVED(ret,
     87 				   "Unable to unlock double-locked recursive mutex in clean-up handler 1");
     88 		}
     89 	}
     90 	return;
     91 }
     92 
     93 /**** Second handler
     94  *  This one will trigger an action in main thread, while we are owning the mutex
     95  */
     96 void clnp2(void *arg)
     97 {
     98 	int ret;
     99 
    100 	(void) arg;
    101 
    102 	do {
    103 		ret = sem_post(&(data.semA));
    104 	} while ((ret != 0) && (errno == EINTR));
    105 	if (ret != 0) {
    106 		UNRESOLVED(errno, "Sem post failed in cleanup handler 2");
    107 	}
    108 
    109 	do {
    110 		ret = sem_wait(&(data.semB));
    111 	} while ((ret != 0) && (errno == EINTR));
    112 	if (ret != 0) {
    113 		UNRESOLVED(errno, "Sem wait failed in cleanup handler 2");
    114 	}
    115 
    116 	return;
    117 }
    118 
    119 /**** Third handler
    120  *  Will actually unlock the mutex, then try to unlock second time to check an error is returned
    121  */
    122 void clnp3(void *arg)
    123 {
    124 	int ret;
    125 
    126 	(void) arg;
    127 
    128 	ret = pthread_mutex_unlock(&(data.mtx));
    129 	if (ret != 0) {
    130 		UNRESOLVED(ret, "Unable to unlock mutex in clean-up handler 3");
    131 	}
    132 
    133 	if ((data.type == PTHREAD_MUTEX_ERRORCHECK)
    134 	    || (data.type == PTHREAD_MUTEX_RECURSIVE)) {
    135 		ret = pthread_mutex_unlock(&(data.mtx));
    136 		if (ret == 0) {
    137 			UNRESOLVED(ret,
    138 				   "Was able to unlock unlocked mutex in clean-up handler 3");
    139 		}
    140 	}
    141 
    142 	return;
    143 }
    144 
    145 /**** Thread function
    146  * This function will lock the mutex, then install the cleanup handlers
    147  * and wait for the cond. At this point it will be canceled.
    148  */
    149 void *threaded(void *arg)
    150 {
    151 	int ret;
    152 
    153 	(void) arg;
    154 
    155 	struct timespec ts;
    156 
    157 	ret = clock_gettime(data.cid, &ts);
    158 	if (ret != 0) {
    159 		UNRESOLVED(ret, "Unable to get time from clock");
    160 	}
    161 
    162 	ts.tv_sec += 30;
    163 
    164 	ret = pthread_mutex_lock(&(data.mtx));
    165 	if (ret != 0) {
    166 		UNRESOLVED(ret, "Failed to lock the mutex in thread");
    167 	}
    168 
    169 	do {
    170 		ret = sem_post(&(data.semA));
    171 	} while ((ret != 0) && (errno == EINTR));
    172 	if (ret != 0) {
    173 		UNRESOLVED(errno, "Sem post failed in thread");
    174 	}
    175 
    176 	pthread_cleanup_push(clnp3, NULL);
    177 	pthread_cleanup_push(clnp2, NULL);
    178 	pthread_cleanup_push(clnp1, NULL);
    179 
    180 	do {
    181 		ret = pthread_cond_timedwait(&(data.cnd), &(data.mtx), &ts);
    182 	} while ((ret == 0) && (data.bool == 0));
    183 
    184 	if (ret != 0) {
    185 		UNRESOLVED(ret, "Timedwait failed");
    186 	}
    187 
    188 	/* We will exit even if the error is timedwait */
    189 	/* If we are here, the thread was not canceled */
    190 	FAILED("The thread has not been canceled");
    191 
    192 	pthread_cleanup_pop(0);
    193 	pthread_cleanup_pop(0);
    194 	pthread_cleanup_pop(1);
    195 
    196 	return NULL;
    197 }
    198 
    199 int main(void)
    200 {
    201 	int ret;
    202 	unsigned int i;
    203 	void *rc;
    204 
    205 	pthread_mutexattr_t ma;
    206 	pthread_condattr_t ca;
    207 	pthread_t th;
    208 
    209 	long altclk_ok, pshared_ok;
    210 
    211 	struct {
    212 		char altclk;	/* Want to use alternative clock */
    213 		char pshared;	/* Want to use process-shared primitives */
    214 		int type;	/* mutex type */
    215 		char *descr;	/* Description of the case */
    216 
    217 	} scenar[] = { {
    218 	0, 0, PTHREAD_MUTEX_NORMAL, "Normal mutex"}
    219 #ifdef USE_ALTCLK
    220 	, {
    221 	1, 0, PTHREAD_MUTEX_NORMAL, "Normal mutex + altclock cond"}
    222 	, {
    223 	1, 1, PTHREAD_MUTEX_NORMAL, "PShared mutex + altclock cond"}
    224 #endif
    225 	, {
    226 	0, 1, PTHREAD_MUTEX_NORMAL, "Pshared mutex"}
    227 #ifndef WITHOUT_XOPEN
    228 	, {
    229 	0, 0, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck mutex"}
    230 	, {
    231 	0, 0, PTHREAD_MUTEX_RECURSIVE, "Recursive mutex"}
    232 #ifdef USE_ALTCLK
    233 	, {
    234 	1, 0, PTHREAD_MUTEX_RECURSIVE, "Recursive mutex + altclock cond"}
    235 	, {
    236 	1, 0, PTHREAD_MUTEX_ERRORCHECK,
    237 		    "Errorcheck mutex + altclock cond"}
    238 	, {
    239 	1, 1, PTHREAD_MUTEX_RECURSIVE,
    240 		    "Recursive pshared mutex + altclock cond"}
    241 	, {
    242 	1, 1, PTHREAD_MUTEX_ERRORCHECK,
    243 		    "Errorcheck pshared mutex + altclock cond"}
    244 #endif
    245 	, {
    246 	0, 1, PTHREAD_MUTEX_RECURSIVE, "Recursive pshared mutex"}
    247 	, {
    248 	0, 1, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck pshared mutex"}
    249 #endif
    250 	};
    251 
    252 	output_init();
    253 
    254 	/* Initialize the constants */
    255 	altclk_ok = sysconf(_SC_CLOCK_SELECTION);
    256 	if (altclk_ok > 0)
    257 		altclk_ok = sysconf(_SC_MONOTONIC_CLOCK);
    258 #ifndef USE_ALTCLK
    259 	if (altclk_ok > 0)
    260 		output
    261 		    ("Implementation supports the MONOTONIC CLOCK but option is disabled in test.\n");
    262 #endif
    263 
    264 	pshared_ok = sysconf(_SC_THREAD_PROCESS_SHARED);
    265 
    266 #if VERBOSE > 0
    267 	output("Test starting\n");
    268 	output(" Process-shared primitive %s be tested\n",
    269 	       (pshared_ok > 0) ? "will" : "won't");
    270 	output(" Alternative clock for cond %s be tested\n",
    271 	       (altclk_ok > 0) ? "will" : "won't");
    272 #endif
    273 
    274 	ret = sem_init(&(data.semA), 0, 0);
    275 	if (ret != 0) {
    276 		UNRESOLVED(errno, "Unable to init sem A");
    277 	}
    278 
    279 	ret = sem_init(&(data.semB), 0, 0);
    280 	if (ret != 0) {
    281 		UNRESOLVED(errno, "Unable to init sem B");
    282 	}
    283 
    284 	for (i = 0; i < (sizeof(scenar) / sizeof(scenar[0])); i++) {
    285 #if VERBOSE > 1
    286 		output("Starting test for %s\n", scenar[i].descr);
    287 #endif
    288 
    289 		/* Initialize the data structure */
    290 		ret = pthread_mutexattr_init(&ma);
    291 		if (ret != 0) {
    292 			UNRESOLVED(ret, "Mutex attribute object init failed");
    293 		}
    294 
    295 		ret = pthread_mutexattr_settype(&ma, scenar[i].type);
    296 		if (ret != 0) {
    297 			UNRESOLVED(ret, "Unable to set mutex type");
    298 		}
    299 
    300 		if ((pshared_ok > 0) && (scenar[i].pshared != 0)) {
    301 			ret =
    302 			    pthread_mutexattr_setpshared(&ma,
    303 							 PTHREAD_PROCESS_SHARED);
    304 			if (ret != 0) {
    305 				UNRESOLVED(ret,
    306 					   "Unable to set mutex process-shared");
    307 			}
    308 		}
    309 
    310 		ret = pthread_condattr_init(&ca);
    311 		if (ret != 0) {
    312 			UNRESOLVED(ret, "Cond attribute object init failed");
    313 		}
    314 
    315 		if ((pshared_ok > 0) && (scenar[i].pshared != 0)) {
    316 			ret =
    317 			    pthread_condattr_setpshared(&ca,
    318 							PTHREAD_PROCESS_SHARED);
    319 			if (ret != 0) {
    320 				UNRESOLVED(ret,
    321 					   "Unable to set cond process-shared");
    322 			}
    323 		}
    324 #ifdef USE_ALTCLK
    325 		if ((altclk_ok > 0) && (scenar[i].altclk != 0)) {
    326 			ret = pthread_condattr_setclock(&ca, CLOCK_MONOTONIC);
    327 			if (ret != 0) {
    328 				UNRESOLVED(ret,
    329 					   "Unable to set alternative (monotonic) clock for cond");
    330 			}
    331 		}
    332 #endif
    333 
    334 		ret = pthread_mutex_init(&(data.mtx), &ma);
    335 		if (ret != 0) {
    336 			UNRESOLVED(ret, "Unable to init mutex");
    337 		}
    338 
    339 		ret = pthread_cond_init(&(data.cnd), &ca);
    340 		if (ret != 0) {
    341 			UNRESOLVED(ret, "Unable to initialize condvar");
    342 		}
    343 
    344 		ret = pthread_mutexattr_gettype(&ma, &(data.type));
    345 		if (ret != 0) {
    346 			UNRESOLVED(ret, "Unable to get type from mutex attr");
    347 		}
    348 #ifdef USE_ALTCLK
    349 		ret = pthread_condattr_getclock(&ca, &(data.cid));
    350 		if (ret != 0) {
    351 			UNRESOLVED(ret,
    352 				   "Unable to get clock ID from cond attr");
    353 		}
    354 #else
    355 		data.cid = CLOCK_REALTIME;
    356 #endif
    357 
    358 		data.bool = 0;
    359 
    360 		/** Data is ready, create the thread */
    361 #if VERBOSE > 1
    362 		output("Initialization OK, starting thread\n");
    363 #endif
    364 
    365 		ret = pthread_create(&th, NULL, threaded, NULL);
    366 		if (ret != 0) {
    367 			UNRESOLVED(ret, "Thread creation failed");
    368 		}
    369 
    370 		/** Wait for the thread to be waiting */
    371 		do {
    372 			ret = sem_wait(&(data.semA));
    373 		} while ((ret != 0) && (errno == EINTR));
    374 		if (ret != 0) {
    375 			UNRESOLVED(errno, "Sem wait failed in main");
    376 		}
    377 
    378 		ret = pthread_mutex_lock(&(data.mtx));
    379 		if (ret != 0) {
    380 			UNRESOLVED(ret, "Unable to lock mutex in main");
    381 		}
    382 
    383 		data.bool = 1;
    384 
    385 		/** Cancel the thread */
    386 		ret = pthread_cancel(th);
    387 		if (ret != 0) {
    388 			UNRESOLVED(ret, "Thread cancelation failed");
    389 		}
    390 
    391 		sched_yield();
    392 #ifndef WITHOUT_XOPEN
    393 		usleep(100);
    394 #endif
    395 
    396 		ret = pthread_mutex_unlock(&(data.mtx));
    397 		if (ret != 0) {
    398 			UNRESOLVED(ret, "Unable to unlock mutex in main");
    399 		}
    400 
    401 		/** Wait for the thread to be executing second cleanup handler */
    402 		do {
    403 			ret = sem_wait(&(data.semA));
    404 		} while ((ret != 0) && (errno == EINTR));
    405 		if (ret != 0) {
    406 			UNRESOLVED(errno, "Sem wait failed in main");
    407 		}
    408 
    409 		/** Here the child should own the mutex, we check this */
    410 		ret = pthread_mutex_trylock(&(data.mtx));
    411 		if (ret == 0) {
    412 			FAILED
    413 			    ("The child did not own the mutex inside the cleanup handler");
    414 		}
    415 
    416 		/** Let the cleanups go on */
    417 		do {
    418 			ret = sem_post(&(data.semB));
    419 		} while ((ret != 0) && (errno == EINTR));
    420 		if (ret != 0) {
    421 			UNRESOLVED(errno, "Sem post failed in main");
    422 		}
    423 
    424 		/** Join the thread */
    425 		ret = pthread_join(th, &rc);
    426 		if (ret != 0) {
    427 			UNRESOLVED(ret, "Unable to join the thread");
    428 		}
    429 		if (rc != PTHREAD_CANCELED) {
    430 			FAILED("thread was not canceled");
    431 		}
    432 #if VERBOSE > 1
    433 		output("Test passed for %s\n", scenar[i].descr);
    434 #endif
    435 
    436 		/* Destroy datas */
    437 		ret = pthread_cond_destroy(&(data.cnd));
    438 		if (ret != 0) {
    439 			UNRESOLVED(ret, "Cond destroy failed");
    440 		}
    441 
    442 		ret = pthread_mutex_destroy(&(data.mtx));
    443 		if (ret != 0) {
    444 			UNRESOLVED(ret, "Mutex destroy failed");
    445 		}
    446 
    447 		ret = pthread_condattr_destroy(&ca);
    448 		if (ret != 0) {
    449 			UNRESOLVED(ret, "Cond attribute destroy failed");
    450 		}
    451 
    452 		ret = pthread_mutexattr_destroy(&ma);
    453 		if (ret != 0) {
    454 			UNRESOLVED(ret, "Mutex attr destroy failed");
    455 		}
    456 	}			/* Proceed to next case */
    457 
    458 	ret = sem_destroy(&(data.semA));
    459 	if (ret != 0) {
    460 		UNRESOLVED(errno, "Sem destroy failed");
    461 	}
    462 
    463 	ret = sem_destroy(&(data.semB));
    464 	if (ret != 0) {
    465 		UNRESOLVED(errno, "Sem destroy failed");
    466 	}
    467 
    468 	PASSED;
    469 }
    470