Home | History | Annotate | Download | only in pthread_mutex_trylock
      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 file is a stress test for the pthread_mutex_trylock function.
     18  *
     19  * It aims to check that when EBUSY is returned, the mutex has not been locked.
     20 
     21  * The steps are:
     22  * -> do
     23  *   -> Set up a timeout. The test fails if this timeout expires.
     24  *   -> lock the mutex
     25  *   -> create N threads.
     26  *     -> each thread loops on pthread_mutex_trylock while ret == EBUSY and go_on is true..
     27  *     -> if ret == 0 && go_on is true, wait on a barrier then go_on = 0.
     28  *     -> if ret == 0 unlock the mutex
     29  *   -> do
     30  *     -> unlock the mutex
     31  *     -> yield
     32  *     -> trylock the mutex
     33  *   -> while we don't get EBUSY.
     34  *   -> wait on the barrier to unblock the thread which got the 0 error code.
     35  *       If no thread got this code but one got the mutex,
     36  *       the main thread will hang here and the timeout will expire (test FAILS).
     37  *   -> join all the threads
     38  * -> while we don't receive SIGUSR1
     39  */
     40 
     41  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
     42 #define _POSIX_C_SOURCE 200112L
     43 
     44  /* We need the XSI extention for the mutex attributes */
     45 #ifndef WITHOUT_XOPEN
     46 #define _XOPEN_SOURCE	600
     47 #endif
     48  /********************************************************************************************/
     49 /****************************** standard includes *****************************************/
     50 /********************************************************************************************/
     51 #include <pthread.h>
     52 #include <stdarg.h>
     53 #include <stdio.h>
     54 #include <stdlib.h>
     55 #include <unistd.h>
     56 
     57 #include <errno.h>
     58 #include <semaphore.h>
     59 #include <signal.h>
     60 
     61 /********************************************************************************************/
     62 /******************************   Test framework   *****************************************/
     63 /********************************************************************************************/
     64 #include "testfrmw.h"
     65 #include "testfrmw.c"
     66  /* This header is responsible for defining the following macros:
     67   * UNRESOLVED(ret, descr);
     68   *    where descr is a description of the error and ret is an int (error code for example)
     69   * FAILED(descr);
     70   *    where descr is a short text saying why the test has failed.
     71   * PASSED();
     72   *    No parameter.
     73   *
     74   * Both three macros shall terminate the calling process.
     75   * The testcase shall not terminate in any other maneer.
     76   *
     77   * The other file defines the functions
     78   * void output_init()
     79   * void output(char * string, ...)
     80   *
     81   * Those may be used to output information.
     82   */
     83 
     84 /********************************************************************************************/
     85 /********************************** Configuration ******************************************/
     86 /********************************************************************************************/
     87 #ifndef VERBOSE
     88 #define VERBOSE 1
     89 #endif
     90 
     91 #ifndef SCALABILITY_FACTOR
     92 #define SCALABILITY_FACTOR 1
     93 #endif
     94 
     95 #define NCHILDREN  (20 * SCALABILITY_FACTOR)
     96 
     97 #define TIMEOUT  (120 * SCALABILITY_FACTOR)
     98 
     99 /********************************************************************************************/
    100 /***********************************    Test case   *****************************************/
    101 /********************************************************************************************/
    102 
    103 char do_it = 1;
    104 
    105 /* Signal handler which will stop the stress run */
    106 void sighdl(int sig)
    107 {
    108 	do {
    109 		do_it = 0;
    110 	}
    111 	while (do_it);
    112 }
    113 
    114 /* Timeout thread */
    115 void *timer(void *arg)
    116 {
    117 	unsigned int to = TIMEOUT;
    118 	do {
    119 		to = sleep(to);
    120 	}
    121 	while (to > 0);
    122 	FAILED
    123 	    ("Operation timed out. EBUSY was returned while a thread acquired the mutex?.");
    124 	return NULL;		/* For compiler */
    125 }
    126 
    127 /* Test specific data */
    128 char go_on = 0;
    129 
    130 typedef struct {
    131 	pthread_mutex_t *mtx;
    132 	pthread_barrier_t *bar;
    133 } testdata_t;
    134 
    135 struct _scenar {
    136 	int m_type;		/* Mutex type to use */
    137 	int m_pshared;		/* 0: mutex is process-private (default) ~ !0: mutex is process-shared, if supported */
    138 	char *descr;		/* Case description */
    139 } scenarii[] = {
    140 	{
    141 	PTHREAD_MUTEX_DEFAULT, 0, "Default mutex"}
    142 #ifndef WITHOUT_XOPEN
    143 	, {
    144 	PTHREAD_MUTEX_NORMAL, 0, "Normal mutex"}
    145 	, {
    146 	PTHREAD_MUTEX_ERRORCHECK, 0, "Errorcheck mutex"}
    147 	, {
    148 	PTHREAD_MUTEX_RECURSIVE, 0, "Recursive mutex"}
    149 #endif
    150 
    151 	, {
    152 	PTHREAD_MUTEX_DEFAULT, 1, "Pshared mutex"}
    153 #ifndef WITHOUT_XOPEN
    154 	, {
    155 	PTHREAD_MUTEX_NORMAL, 1, "Pshared Normal mutex"}
    156 	, {
    157 	PTHREAD_MUTEX_ERRORCHECK, 1, "Pshared Errorcheck mutex"}
    158 	, {
    159 	PTHREAD_MUTEX_RECURSIVE, 1, "Pshared Recursive mutex"}
    160 #endif
    161 };
    162 
    163 #define NSCENAR (sizeof(scenarii)/sizeof(scenarii[0]))
    164 
    165 void *threaded(void *arg)
    166 {
    167 	int ret = 0, ret2 = 0;
    168 	testdata_t *td = (testdata_t *) arg;
    169 
    170 	/* do */
    171 	do {
    172 		/* trylock the mutex */
    173 		ret = pthread_mutex_trylock(td->mtx);
    174 
    175 		/* yield */
    176 		sched_yield();
    177 
    178 	}
    179 	/* while trylock returns EBUSY and go_on == 1 */
    180 	while ((ret == EBUSY) && (go_on == 1));
    181 
    182 	/* if go_on==1 and ret == 0 */
    183 	if ((go_on == 1) && (ret == 0)) {
    184 #if VERBOSE > 6
    185 		output("[child %p] I got the mutex\n", pthread_self());
    186 #endif
    187 
    188 		/* barrier */
    189 		ret2 = pthread_barrier_wait(td->bar);
    190 		if ((ret2 != 0) && (ret2 != PTHREAD_BARRIER_SERIAL_THREAD)) {
    191 			UNRESOLVED(ret2, "Pthread_barrier_wait failed");
    192 		}
    193 
    194 		/* go_on = 0 */
    195 		go_on = 0;
    196 	}
    197 
    198 	/* if ret == 0 */
    199 	if (ret == 0) {
    200 		/* Unlock the mutex */
    201 		ret = pthread_mutex_unlock(td->mtx);
    202 		if (ret != 0) {
    203 			UNRESOLVED(ret, "Failed to unlock the mutex");
    204 		}
    205 	}
    206 
    207 	/* end of thread */
    208 	return NULL;
    209 }
    210 
    211 int main(int argc, char *argv[])
    212 {
    213 	int ret;
    214 	struct sigaction sa;
    215 
    216 	pthread_t t_child[NCHILDREN];
    217 
    218 	pthread_t t_timer;
    219 
    220 	testdata_t td;
    221 
    222 	int i, ch;
    223 	long pshared;
    224 	pthread_mutex_t mtx[NSCENAR + 2];
    225 	pthread_mutexattr_t ma;
    226 	pthread_barrier_t bar;
    227 
    228 	/* Initialize output */
    229 	output_init();
    230 
    231 	/* System abilities */
    232 	pshared = sysconf(_SC_THREAD_PROCESS_SHARED);
    233 
    234 	/* Register the signal handler for SIGUSR1 */
    235 	sigemptyset(&sa.sa_mask);
    236 	sa.sa_flags = 0;
    237 	sa.sa_handler = sighdl;
    238 	if ((ret = sigaction(SIGUSR1, &sa, NULL))) {
    239 		UNRESOLVED(ret, "Unable to register signal handler");
    240 	}
    241 	if ((ret = sigaction(SIGALRM, &sa, NULL))) {
    242 		UNRESOLVED(ret, "Unable to register signal handler");
    243 	}
    244 #if VERBOSE > 1
    245 	output("[parent] Signal handler registered\n");
    246 #endif
    247 
    248 	/* Initialize the barrier */
    249 	ret = pthread_barrier_init(&bar, NULL, 2);
    250 	if (ret != 0) {
    251 		UNRESOLVED(ret, "Barrier init failed");
    252 	}
    253 	td.bar = &bar;
    254 
    255 	/* Initialize every mutexattr & mutex objects */
    256 	for (i = 0; i < NSCENAR; i++) {
    257 		ret = pthread_mutexattr_init(&ma);
    258 		if (ret != 0) {
    259 			UNRESOLVED(ret,
    260 				   "[parent] Unable to initialize the mutex attribute object");
    261 		}
    262 #ifndef WITHOUT_XOPEN
    263 		/* Set the mutex type */
    264 		ret = pthread_mutexattr_settype(&ma, scenarii[i].m_type);
    265 		if (ret != 0) {
    266 			UNRESOLVED(ret, "[parent] Unable to set mutex type");
    267 		}
    268 #endif
    269 		/* Set the pshared attributes, if supported */
    270 		if ((pshared > 0) && (scenarii[i].m_pshared != 0)) {
    271 			ret =
    272 			    pthread_mutexattr_setpshared(&ma,
    273 							 PTHREAD_PROCESS_SHARED);
    274 			if (ret != 0) {
    275 				UNRESOLVED(ret,
    276 					   "[parent] Unable to set the mutex process-shared");
    277 			}
    278 		}
    279 
    280 		/* Initialize the mutex */
    281 		ret = pthread_mutex_init(&mtx[i], &ma);
    282 		if (ret != 0) {
    283 			UNRESOLVED(ret, "[parent] Mutex init failed");
    284 		}
    285 
    286 		/* Destroy the ma object */
    287 		ret = pthread_mutexattr_destroy(&ma);
    288 		if (ret != 0) {
    289 			UNRESOLVED(ret,
    290 				   "Failed to destroy the mutexattr object");
    291 		}
    292 	}
    293 	/* Default mutexattr object */
    294 	ret = pthread_mutexattr_init(&ma);
    295 	if (ret != 0) {
    296 		UNRESOLVED(ret,
    297 			   "[parent] Unable to initialize the mutex attribute object");
    298 	}
    299 	ret = pthread_mutex_init(&mtx[i], &ma);
    300 	if (ret != 0) {
    301 		UNRESOLVED(ret, "[parent] Mutex init failed");
    302 	}
    303 	ret = pthread_mutexattr_destroy(&ma);
    304 	if (ret != 0) {
    305 		UNRESOLVED(ret, "Failed to destroy the mutexattr object");
    306 	}
    307 	/* Default mutex */
    308 	ret = pthread_mutex_init(&mtx[i + 1], NULL);
    309 	if (ret != 0) {
    310 		UNRESOLVED(ret, "[parent] Mutex init failed");
    311 	}
    312 
    313 	i = 0;
    314 	/* While we are not asked to stop */
    315 	while (do_it) {
    316 		/* Start the timeout thread */
    317 		ret = pthread_create(&t_timer, NULL, timer, NULL);
    318 		if (ret != 0) {
    319 			UNRESOLVED(ret, "Unable to create timer thread");
    320 		}
    321 
    322 		/* Set the td pointer to the next mutex */
    323 		td.mtx = &mtx[i];
    324 
    325 		/* lock this mutex */
    326 		ret = pthread_mutex_lock(td.mtx);
    327 		if (ret != 0) {
    328 			UNRESOLVED(ret, "Failed to lock a mutex");
    329 		}
    330 
    331 		/* go_on = 1 */
    332 		go_on = 1;
    333 
    334 		/* Start the children */
    335 		for (ch = 0; ch < NCHILDREN; ch++) {
    336 			ret = pthread_create(&t_child[ch], NULL, threaded, &td);
    337 			if (ret != 0) {
    338 				UNRESOLVED(ret,
    339 					   "Failed to create enough threads");
    340 			}
    341 		}
    342 #if VERBOSE > 5
    343 		output("[parent] The children are running...\n");
    344 #endif
    345 
    346 		/* do */
    347 		do {
    348 			/* unlock the mutex */
    349 			ret = pthread_mutex_unlock(td.mtx);
    350 			if (ret != 0) {
    351 				UNRESOLVED(ret, "Failed to unlcok the mutex");
    352 			}
    353 
    354 			/* yield */
    355 			sched_yield();
    356 
    357 			/* trylock the mutex again */
    358 			ret = pthread_mutex_trylock(td.mtx);
    359 		}
    360 		/* while trylock succeeds */
    361 		while (ret == 0);
    362 		if (ret != EBUSY) {
    363 			UNRESOLVED(ret, "An unexpected error occured");
    364 		}
    365 #if VERBOSE > 6
    366 		output
    367 		    ("[parent] Mutex is busy, a child shall be waiting on the barrier\n");
    368 #endif
    369 
    370 		/* barrier */
    371 		ret = pthread_barrier_wait(&bar);
    372 		if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) {
    373 			UNRESOLVED(ret, "Pthread_barrier_wait failed");
    374 		}
    375 
    376 		/* cancel the timeout thread */
    377 		ret = pthread_cancel(t_timer);
    378 		if (ret != 0) {
    379 			UNRESOLVED(ret, "Failed to cancel the timeout thread");
    380 		}
    381 
    382 		/* join every threads (incl. the timeout) */
    383 		ret = pthread_join(t_timer, NULL);
    384 		if (ret != 0) {
    385 			UNRESOLVED(ret, "Failed to join timeout thread");
    386 		}
    387 		for (ch = 0; ch < NCHILDREN; ch++) {
    388 			ret = pthread_join(t_child[ch], NULL);
    389 			if (ret != 0) {
    390 				UNRESOLVED(ret, "Failed to join a child");
    391 			}
    392 		}
    393 
    394 		/* next mutex */
    395 		i++;
    396 		i %= NSCENAR + 2;
    397 	}
    398 
    399 	/* destroy the barrier & mutexes objects */
    400 	ret = pthread_barrier_destroy(&bar);
    401 	if (ret != 0) {
    402 		UNRESOLVED(ret, "Failed to destroy the barrier");
    403 	}
    404 
    405 	for (i = 0; i < NSCENAR + 2; i++) {
    406 		ret = pthread_mutex_destroy(&mtx[i]);
    407 		if (ret != 0) {
    408 			UNRESOLVED(ret, "Failed to destroy a mutex");
    409 		}
    410 	}
    411 
    412 #if VERBOSE > 0
    413 	output("pthread_mutex_trylock stress test passed\n");
    414 #endif
    415 
    416 	/* test passed */
    417 	PASSED;
    418 }
    419