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