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 sample test aims to check the following assertion:
     18  *
     19  * If the mutex was already locked, the call returns EBUSY immediatly.
     20 
     21  * The steps are:
     22  * -> Set a timeout.
     23  * -> For each kind of mutex,
     24  *   -> Lock the mutex.
     25  *   -> create a new child (either thread or process)
     26  *      -> the new child trylock the mutex. It shall fail.
     27  *   -> undo everything.
     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     and the mkstemp() routine */
     35 #ifndef WITHOUT_XOPEN
     36 #define _XOPEN_SOURCE	600
     37 #endif
     38  /********************************************************************************************/
     39 /****************************** standard includes *****************************************/
     40 /********************************************************************************************/
     41 #include <pthread.h>
     42 #include <stdarg.h>
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <unistd.h>
     46 
     47 #include <errno.h>
     48 #include <sys/wait.h>
     49 #include <sys/mman.h>
     50 #include <string.h>
     51 
     52 /********************************************************************************************/
     53 /******************************   Test framework   *****************************************/
     54 /********************************************************************************************/
     55 #include "../testfrmw/testfrmw.h"
     56 #include "../testfrmw/testfrmw.c"
     57  /* This header is responsible for defining the following macros:
     58   * UNRESOLVED(ret, descr);
     59   *    where descr is a description of the error and ret is an int (error code for example)
     60   * FAILED(descr);
     61   *    where descr is a short text saying why the test has failed.
     62   * PASSED();
     63   *    No parameter.
     64   *
     65   * Both three macros shall terminate the calling process.
     66   * The testcase shall not terminate in any other maneer.
     67   *
     68   * The other file defines the functions
     69   * void output_init()
     70   * void output(char * string, ...)
     71   *
     72   * Those may be used to output information.
     73   */
     74 
     75 /********************************************************************************************/
     76 /********************************** Configuration ******************************************/
     77 /********************************************************************************************/
     78 #ifndef VERBOSE
     79 #define VERBOSE 1
     80 #endif
     81 
     82 /********************************************************************************************/
     83 /***********************************    Test case   *****************************************/
     84 /********************************************************************************************/
     85 typedef struct {
     86 	pthread_mutex_t mtx;
     87 	int status;		/* error code */
     88 } testdata_t;
     89 
     90 struct _scenar {
     91 	int m_type;		/* Mutex type to use */
     92 	int m_pshared;		/* 0: mutex is process-private (default) ~ !0: mutex is process-shared, if supported */
     93 	int fork;		/* 0: Test between threads. ~ !0: Test across processes, if supported (mmap) */
     94 	char *descr;		/* Case description */
     95 } scenarii[] = {
     96 	{
     97 	PTHREAD_MUTEX_DEFAULT, 0, 0, "Default mutex"}
     98 #ifndef WITHOUT_XOPEN
     99 	, {
    100 	PTHREAD_MUTEX_NORMAL, 0, 0, "Normal mutex"}
    101 	, {
    102 	PTHREAD_MUTEX_ERRORCHECK, 0, 0, "Errorcheck mutex"}
    103 	, {
    104 	PTHREAD_MUTEX_RECURSIVE, 0, 0, "Recursive mutex"}
    105 #endif
    106 
    107 	, {
    108 	PTHREAD_MUTEX_DEFAULT, 1, 0, "Pshared mutex"}
    109 #ifndef WITHOUT_XOPEN
    110 	, {
    111 	PTHREAD_MUTEX_NORMAL, 1, 0, "Pshared Normal mutex"}
    112 	, {
    113 	PTHREAD_MUTEX_ERRORCHECK, 1, 0, "Pshared Errorcheck mutex"}
    114 	, {
    115 	PTHREAD_MUTEX_RECURSIVE, 1, 0, "Pshared Recursive mutex"}
    116 #endif
    117 
    118 	, {
    119 	PTHREAD_MUTEX_DEFAULT, 1, 1, "Pshared mutex across processes"}
    120 #ifndef WITHOUT_XOPEN
    121 	, {
    122 	PTHREAD_MUTEX_NORMAL, 1, 1,
    123 		    "Pshared Normal mutex across processes"}
    124 	, {
    125 	PTHREAD_MUTEX_ERRORCHECK, 1, 1,
    126 		    "Pshared Errorcheck mutex across processes"}
    127 	, {
    128 	PTHREAD_MUTEX_RECURSIVE, 1, 1,
    129 		    "Pshared Recursive mutex across processes"}
    130 #endif
    131 };
    132 
    133 #define NSCENAR (sizeof(scenarii)/sizeof(scenarii[0]))
    134 
    135 /* The test function will only perform a trylock operation then return. */
    136 void *tf(void *arg)
    137 {
    138 	testdata_t *td = (testdata_t *) arg;
    139 
    140 	td->status = pthread_mutex_trylock(&(td->mtx));
    141 
    142 	if (td->status == 0) {
    143 		int ret;
    144 
    145 		ret = pthread_mutex_unlock(&(td->mtx));
    146 		if (ret != 0) {
    147 			UNRESOLVED(ret, "Failed to unlock a locked semaphore");
    148 		}
    149 	}
    150 
    151 	return NULL;
    152 }
    153 
    154 /* Main entry point. */
    155 int main(void)
    156 {
    157 	int ret;
    158 	int sc;
    159 	pthread_mutexattr_t ma;
    160 
    161 	testdata_t *td;
    162 	testdata_t alternativ;
    163 
    164 	int do_fork;
    165 
    166 	pid_t child_pr = 0, chkpid;
    167 	int status;
    168 	pthread_t child_th;
    169 
    170 	long pshared, mf;
    171 
    172 	/* Initialize output */
    173 	output_init();
    174 
    175 	/* Initialize the timeout */
    176 	alarm(30);
    177 
    178 	/* Test system abilities */
    179 	pshared = sysconf(_SC_THREAD_PROCESS_SHARED);
    180 	mf = sysconf(_SC_MAPPED_FILES);
    181 
    182 #if VERBOSE > 0
    183 	output("Test starting\n");
    184 	output("System abilities:\n");
    185 	output(" TSH : %li\n", pshared);
    186 	output(" MF  : %li\n", mf);
    187 	if ((mf < 0) || (pshared < 0))
    188 		output("Process-shared attributes won't be tested\n");
    189 #endif
    190 
    191 #ifdef WITHOUT_XOPEN
    192 #if VERBOSE > 0
    193 	output
    194 	    ("As XSI extension is disabled, we won't test the feature across process\n");
    195 #endif
    196 	mf = -1;
    197 #endif
    198 
    199 /**********
    200  * Allocate space for the testdata structure
    201  */
    202 	if (mf < 0) {
    203 		/* Cannot mmap a file (or not interested in this), we use an alternative method */
    204 		td = &alternativ;
    205 		pshared = -1;	/* We won't do this testing anyway */
    206 #if VERBOSE > 0
    207 		output("Testdata allocated in the process memory.\n");
    208 #endif
    209 	}
    210 #ifndef WITHOUT_XOPEN
    211 	else {
    212 		/* We will place the test data in a mmaped file */
    213 		char filename[] = "/tmp/mutex_trylock_4-2-XXXXXX";
    214 		size_t sz;
    215 		void *mmaped;
    216 		int fd;
    217 		char *tmp;
    218 
    219 		/* We now create the temp files */
    220 		fd = mkstemp(filename);
    221 		if (fd == -1) {
    222 			UNRESOLVED(errno,
    223 				   "Temporary file could not be created");
    224 		}
    225 
    226 		/* and make sure the file will be deleted when closed */
    227 		unlink(filename);
    228 
    229 #if VERBOSE > 1
    230 		output("Temp file created (%s).\n", filename);
    231 #endif
    232 
    233 		sz = (size_t) sysconf(_SC_PAGESIZE);
    234 
    235 		tmp = calloc(1, sz);
    236 		if (tmp == NULL) {
    237 			UNRESOLVED(errno, "Memory allocation failed");
    238 		}
    239 
    240 		/* Write the data to the file.  */
    241 		if (write(fd, tmp, sz) != (ssize_t) sz) {
    242 			UNRESOLVED(sz, "Writting to the file failed");
    243 		}
    244 
    245 		free(tmp);
    246 
    247 		/* Now we can map the file in memory */
    248 		mmaped =
    249 		    mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    250 		if (mmaped == MAP_FAILED) {
    251 			UNRESOLVED(errno, "mmap failed");
    252 		}
    253 
    254 		td = (testdata_t *) mmaped;
    255 
    256 		/* Our datatest structure is now in shared memory */
    257 #if VERBOSE > 1
    258 		output("Testdata allocated in shared memory.\n");
    259 #endif
    260 	}
    261 #endif
    262 
    263 /**********
    264  * For each test scenario, initialize the attributes and other variables.
    265  * Do the whole thing for each time to test.
    266  */
    267 	for (sc = 0; sc < NSCENAR; sc++) {
    268 #if VERBOSE > 1
    269 		output("[parent] Preparing attributes for: %s\n",
    270 		       scenarii[sc].descr);
    271 #endif
    272 		/* set / reset everything */
    273 		do_fork = 0;
    274 		ret = pthread_mutexattr_init(&ma);
    275 		if (ret != 0) {
    276 			UNRESOLVED(ret,
    277 				   "[parent] Unable to initialize the mutex attribute object");
    278 		}
    279 #ifndef WITHOUT_XOPEN
    280 		/* Set the mutex type */
    281 		ret = pthread_mutexattr_settype(&ma, scenarii[sc].m_type);
    282 		if (ret != 0) {
    283 			UNRESOLVED(ret, "[parent] Unable to set mutex type");
    284 		}
    285 #if VERBOSE > 1
    286 		output("[parent] Mutex type : %i\n", scenarii[sc].m_type);
    287 #endif
    288 #endif
    289 
    290 		/* Set the pshared attributes, if supported */
    291 		if ((pshared > 0) && (scenarii[sc].m_pshared != 0)) {
    292 			ret =
    293 			    pthread_mutexattr_setpshared(&ma,
    294 							 PTHREAD_PROCESS_SHARED);
    295 			if (ret != 0) {
    296 				UNRESOLVED(ret,
    297 					   "[parent] Unable to set the mutex process-shared");
    298 			}
    299 #if VERBOSE > 1
    300 			output("[parent] Mutex is process-shared\n");
    301 #endif
    302 		}
    303 #if VERBOSE > 1
    304 		else {
    305 			output("[parent] Mutex is process-private\n");
    306 		}
    307 #endif
    308 
    309 		/* Tell whether the test will be across processes */
    310 		if ((pshared > 0) && (scenarii[sc].fork != 0)) {
    311 			do_fork = 1;
    312 #if VERBOSE > 1
    313 			output("[parent] Child will be a new process\n");
    314 #endif
    315 		}
    316 #if VERBOSE > 1
    317 		else {
    318 			output("[parent] Child will be a new thread\n");
    319 		}
    320 #endif
    321 
    322 /**********
    323  * Initialize the testdata_t structure with the previously defined attributes
    324  */
    325 		/* Initialize the mutex */
    326 		ret = pthread_mutex_init(&(td->mtx), &ma);
    327 		if (ret != 0) {
    328 			UNRESOLVED(ret, "[parent] Mutex init failed");
    329 		}
    330 
    331 		/* Initialize the other datas from the test structure */
    332 		td->status = 0;
    333 
    334 /**********
    335  * Proceed to the actual testing
    336  */
    337 		/* Trylock the mutex twice before creating children */
    338 		ret = pthread_mutex_lock(&(td->mtx));
    339 		if (ret != 0) {
    340 			UNRESOLVED(ret, "[parent] Unable to lock the mutex");
    341 		}
    342 
    343 		/* Create the children */
    344 		if (do_fork != 0) {
    345 			/* We are testing across processes */
    346 			child_pr = fork();
    347 			if (child_pr == -1) {
    348 				UNRESOLVED(errno, "[parent] Fork failed");
    349 			}
    350 
    351 			if (child_pr == 0) {
    352 #if VERBOSE > 3
    353 				output
    354 				    ("[child] Child process is starting...\n");
    355 #endif
    356 
    357 				if (tf((void *)td) != NULL) {
    358 					UNRESOLVED(-1,
    359 						   "[child] Got an unexpected return value from test function");
    360 				} else {
    361 					/* We cannot use the PASSED macro here since it would terminate the output */
    362 					exit(0);
    363 				}
    364 			}
    365 			/* Only the parent process goes further */
    366 		} else {	/* do_fork == 0 */
    367 
    368 			/* We are testing across two threads */
    369 			ret = pthread_create(&child_th, NULL, tf, td);
    370 			if (ret != 0) {
    371 				UNRESOLVED(ret,
    372 					   "[parent] Unable to create the child thread.");
    373 			}
    374 		}
    375 
    376 		/* Wait for the child to terminate */
    377 		if (do_fork != 0) {
    378 			/* We were testing across processes */
    379 			ret = 0;
    380 			chkpid = waitpid(child_pr, &status, 0);
    381 			if (chkpid != child_pr) {
    382 				output("Expected pid: %i. Got %i\n",
    383 				       (int)child_pr, (int)chkpid);
    384 				UNRESOLVED(errno, "Waitpid failed");
    385 			}
    386 			if (WIFSIGNALED(status)) {
    387 				output("Child process killed with signal %d\n",
    388 				       WTERMSIG(status));
    389 				UNRESOLVED(-1, "Child process was killed");
    390 			}
    391 
    392 			if (WIFEXITED(status)) {
    393 				ret = WEXITSTATUS(status);
    394 			} else {
    395 				UNRESOLVED(-1,
    396 					   "Child process was neither killed nor exited");
    397 			}
    398 
    399 			if (ret != 0) {
    400 				exit(ret);	/* Output has already been closed in child */
    401 			}
    402 
    403 		} else {	/* child was a thread */
    404 
    405 			ret = pthread_join(child_th, NULL);
    406 			if (ret != 0) {
    407 				UNRESOLVED(ret,
    408 					   "[parent] Unable to join the thread");
    409 			}
    410 		}
    411 
    412 		/* Check the child status */
    413 		if (td->status != EBUSY) {
    414 			output("Unexpected return value: %d (%s)\n", td->status,
    415 			       strerror(td->status));
    416 			FAILED
    417 			    ("pthread_mutex_trylock() did not return EBUSY in the child");
    418 		}
    419 
    420 		/* Unlock the mutex */
    421 		ret = pthread_mutex_unlock(&(td->mtx));
    422 		if (ret != 0) {
    423 			UNRESOLVED(ret, "Failed to unlock the mutex");
    424 		}
    425 
    426 /**********
    427  * Destroy the data
    428  */
    429 		ret = pthread_mutex_destroy(&(td->mtx));
    430 		if (ret != 0) {
    431 			UNRESOLVED(ret, "Failed to destroy the mutex");
    432 		}
    433 
    434 		ret = pthread_mutexattr_destroy(&ma);
    435 		if (ret != 0) {
    436 			UNRESOLVED(ret,
    437 				   "Failed to destroy the mutex attribute object");
    438 		}
    439 
    440 	}			/* Proceed to the next scenario */
    441 
    442 #if VERBOSE > 0
    443 	output("Test passed\n");
    444 #endif
    445 
    446 	PASSED;
    447 }
    448