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