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