Home | History | Annotate | Download | only in pthread_mutex_init
      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 
     18  * This sample test aims to check the following assertion:
     19  *
     20  * The macro PTHREAD_MUTEX_INITIALIZER can be used
     21  * to initialize mutexes that are statically allocated.
     22  * The effect are equivalent to dynamic initialization by a call to
     23  * pthread_mutex_init() with parameter attr specified as NULL,
     24  * except that no error checks are performed.
     25  *
     26  * The steps are:
     27  *  * create two mutexes. One is initialized with NULL attribute,
     28  *       the other is statically initialized with the macro PTHREAD_MUTEX_INITIALIZER.
     29  *  * Compare the following features between the two mutexes:
     30  *      -> Can it cause / detect a deadlock? (attempt to lock a mutex the thread already owns).
     31  *            If detected, do both mutexes cause the same error code?
     32  *      -> Is an error returned when unlocking the mutex in unlocked state?
     33  *            When unlocking the mutex owned by another thread?
     34  *
     35  *
     36  * The test will pass if the results of each feature are the same for the two mutexes
     37  * (making no assumption on what is the default behavior).
     38  * The test will be unresolved if any initialization fails.
     39  * The test will fail if a feature differs between the two mutex objects.
     40  */
     41 
     42  /*
     43   * - adam.li (at) intel.com 2004-05-09
     44   *   Add to PTS. Please refer to http://nptl.bullopensource.org/phpBB/
     45   *   for general information
     46   */
     47 
     48  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
     49 #define _POSIX_C_SOURCE 200112L
     50 /********************************************************************************************/
     51 /****************************** standard includes *****************************************/
     52 /********************************************************************************************/
     53 #include <pthread.h>
     54 #include <semaphore.h>
     55 #include <errno.h>
     56 #include <stdio.h>
     57 #include <unistd.h>
     58 #include <stdarg.h>
     59 #include <stdlib.h>
     60 
     61 /********************************************************************************************/
     62 /******************************   Test framework   *****************************************/
     63 /********************************************************************************************/
     64 #include "../testfrmw/testfrmw.h"
     65 #include "../testfrmw/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 /********************************************************************************************/
     92 /***********************************    Test case   *****************************************/
     93 /********************************************************************************************/
     94 
     95 /**** global variables ****/
     96 pthread_mutex_t *p_mtx;
     97 int retval = 0;
     98 int returned = 0;
     99 int canceled = 0;
    100 sem_t semA, semB;
    101 
    102 /***** Cancelation handlers  *****/
    103 void cleanup_deadlk(void *arg)
    104 {
    105 	canceled = 1;
    106 	pthread_mutex_unlock(p_mtx);
    107 }
    108 
    109 /***** Threads functions *****/
    110 void *deadlk_issue(void *arg)
    111 {
    112 	int ret, tmp;
    113 
    114 	if ((ret = pthread_mutex_lock(p_mtx))) {
    115 		UNRESOLVED(ret, "First mutex lock in deadlk_issue");
    116 	}
    117 	pthread_cleanup_push(cleanup_deadlk, NULL);
    118 	if ((ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &tmp))) {
    119 		UNRESOLVED(ret, "Set cancel type in deadlk_issue");
    120 	}
    121 	if ((ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &tmp))) {
    122 		UNRESOLVED(ret, "Set cancel state in deadlk_issue");
    123 	}
    124 #if VERBOSE >1
    125 	output("Thread releases the semaphore...\n");
    126 #endif
    127 	if ((ret = sem_post(&semA))) {
    128 		UNRESOLVED(errno, "Sem_post in deadlk_issue");
    129 	}
    130 
    131 	returned = 0;
    132 	retval = pthread_mutex_lock(p_mtx);
    133 	returned = 1;
    134 
    135 	if ((ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &tmp))) {
    136 		UNRESOLVED(ret, "Set cancel state in deadlk_issue");
    137 	}
    138 	pthread_cleanup_pop(0);
    139 	return NULL;
    140 }
    141 
    142 void *unlock_issue(void *arg)
    143 {
    144 	int ret;
    145 
    146 #if VERBOSE >1
    147 	output("Locking in child...\n");
    148 #endif
    149 	if ((ret = pthread_mutex_lock(p_mtx))) {
    150 		UNRESOLVED(ret, "First mutex lock in unlock_issue");
    151 	}
    152 
    153 	if ((ret = sem_post(&semA))) {
    154 		UNRESOLVED(errno, "Sem_post in unlock_issue");
    155 	}
    156 
    157 	if ((ret = sem_wait(&semB))) {
    158 		UNRESOLVED(errno, "Sem_wait in unlock_issue");
    159 	}
    160 
    161 	if (retval != 0) {	/* parent thread failed to unlock the mutex) */
    162 #if VERBOSE >1
    163 		output("Unlocking in child...\n");
    164 #endif
    165 		if ((ret = pthread_mutex_unlock(p_mtx))) {
    166 			FAILED
    167 			    ("Mutex unlock returned an error but mutex is unlocked.");
    168 		}
    169 	}
    170 
    171 	return NULL;
    172 }
    173 
    174 /***** main program *****/
    175 int main(void)
    176 {
    177 	pthread_mutex_t mtx_null, mtx_macro = PTHREAD_MUTEX_INITIALIZER;
    178 	pthread_t thr;
    179 
    180 	pthread_mutex_t *tab_mutex[2] = { &mtx_null, &mtx_macro };
    181 	int tab_res[2][3] = { {0, 0, 0}, {0, 0, 0} };
    182 
    183 	int ret;
    184 	void *th_ret;
    185 
    186 	int i;
    187 
    188 	output_init();
    189 #if VERBOSE >1
    190 	output("Test starting...\n");
    191 #endif
    192 
    193 	/* We first initialize the two mutexes. */
    194 	if ((ret = pthread_mutex_init(&mtx_null, NULL))) {
    195 		UNRESOLVED(ret, "NULL mutex init");
    196 	}
    197 
    198 	if ((ret = sem_init(&semA, 0, 0))) {
    199 		UNRESOLVED(errno, "Sem A init");
    200 	}
    201 	if ((ret = sem_init(&semB, 0, 0))) {
    202 		UNRESOLVED(errno, "Sem B init");
    203 	}
    204 #if VERBOSE >1
    205 	output("Data initialized...\n");
    206 #endif
    207 
    208 	/* OK let's go for the first part of the test : abnormals unlocking */
    209 
    210 	/* We first check if unlocking an unlocked mutex returns an error. */
    211 	retval = pthread_mutex_unlock(tab_mutex[0]);
    212 	ret = pthread_mutex_unlock(tab_mutex[1]);
    213 #if VERBOSE >0
    214 	output
    215 	    ("Results for unlock issue #1:\n mutex 1 unlocking returned %i\n mutex 2 unlocking returned %i\n",
    216 	     retval, ret);
    217 #endif
    218 	if (ret != retval) {
    219 		FAILED("Unlocking an unlocked mutex behaves differently.");
    220 	}
    221 
    222 	/* Now we focus on unlocking a mutex lock by another thread */
    223 	for (i = 0; i < 2; i++) {
    224 		p_mtx = tab_mutex[i];
    225 		tab_res[i][0] = 0;
    226 		tab_res[i][1] = 0;
    227 		tab_res[i][2] = 0;
    228 
    229 #if VERBOSE >1
    230 		output("Creating thread (unlock)...\n");
    231 #endif
    232 
    233 		if ((ret = pthread_create(&thr, NULL, unlock_issue, NULL))) {
    234 			UNRESOLVED(ret, "Unlock issue thread create");
    235 		}
    236 
    237 		if ((ret = sem_wait(&semA))) {
    238 			UNRESOLVED(errno,
    239 				   "Sem A wait failed for unlock issue.");
    240 		}
    241 #if VERBOSE >1
    242 		output("Unlocking in parent...\n");
    243 #endif
    244 		retval = pthread_mutex_unlock(p_mtx);
    245 
    246 		if ((ret = sem_post(&semB))) {
    247 			UNRESOLVED(errno,
    248 				   "Sem B post failed for unlock issue.");
    249 		}
    250 
    251 		if ((ret = pthread_join(thr, &th_ret))) {
    252 			UNRESOLVED(ret, "Join thread");
    253 		}
    254 #if VERBOSE >1
    255 		output("Thread joined successfully...\n");
    256 #endif
    257 
    258 		tab_res[i][0] = retval;
    259 	}
    260 #if VERBOSE >0
    261 	output
    262 	    ("Results for unlock issue #2:\n mutex 1 returned %i\n mutex 2 returned %i\n",
    263 	     tab_res[0][0], tab_res[1][0]);
    264 #endif
    265 
    266 	if (tab_res[0][0] != tab_res[1][0]) {
    267 		FAILED("Unlocking an unowned mutex behaves differently.");
    268 	}
    269 
    270 	/* We now are going to test the deadlock issue
    271 	 */
    272 
    273 	/* We start with testing the NULL mutex features */
    274 	for (i = 0; i < 2; i++) {
    275 		p_mtx = tab_mutex[i];
    276 		tab_res[i][0] = 0;
    277 		tab_res[i][1] = 0;
    278 		tab_res[i][2] = 0;
    279 
    280 #if VERBOSE >1
    281 		output("Creating thread (deadlk)...\n");
    282 #endif
    283 
    284 		if ((ret = pthread_create(&thr, NULL, deadlk_issue, NULL))) {
    285 			UNRESOLVED(ret, "Deadlk_issue thread create");
    286 		}
    287 
    288 		/* Now we are waiting the thread is ready to relock the mutex. */
    289 		if ((ret = sem_wait(&semA))) {
    290 			UNRESOLVED(errno, "Sem wait");
    291 		}
    292 
    293 		/* To ensure thread runs until second lock, we yield here */
    294 		sched_yield();
    295 
    296 		/* OK, now we cancel the thread */
    297 		canceled = 0;
    298 #if VERBOSE >1
    299 		output("Cancel thread...\n");
    300 #endif
    301 		if (returned == 0)
    302 			if ((ret = pthread_cancel(thr))) {
    303 				UNRESOLVED(ret, "Cancel thread (deadlk_issue)");
    304 			}
    305 #if VERBOSE >1
    306 		output("Thread canceled...\n");
    307 #endif
    308 
    309 		if ((ret = pthread_join(thr, &th_ret))) {
    310 			UNRESOLVED(ret, "Join thread");
    311 		}
    312 #if VERBOSE >1
    313 		output("Thread joined successfully...\n");
    314 #endif
    315 
    316 		tab_res[i][2] = retval;
    317 		tab_res[i][1] = returned;
    318 		tab_res[i][0] = canceled;
    319 	}
    320 
    321 	/* Now we parse the results */
    322 #if VERBOSE >0
    323 	output
    324 	    ("Results for deadlock issue:\n mutex 1 \t%s\t%s%i\n mutex 2 \t%s\t%s%i\n",
    325 	     tab_res[0][0] ? "deadlock" : "no deadlock",
    326 	     tab_res[0][1] ? "returned " : "did not return ", tab_res[0][2],
    327 	     tab_res[1][0] ? "deadlock" : "no deadlock",
    328 	     tab_res[1][1] ? "returned " : "did not return ", tab_res[1][2]);
    329 #endif
    330 
    331 	if (tab_res[0][0] != tab_res[1][0]) {
    332 		FAILED("One mutex deadlocks, not the other");
    333 	}
    334 
    335 	if (tab_res[0][1] != tab_res[1][1]) {
    336 		UNRESOLVED(tab_res[0][1], "Abnormal situation!");
    337 	}
    338 
    339 	if ((tab_res[0][1] == 1) && (tab_res[0][2] != tab_res[1][2])) {
    340 		FAILED("The locks returned different error codes.");
    341 	}
    342 
    343 	PASSED;
    344 }
    345