Home | History | Annotate | Download | only in pthread_mutex_lock
      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 type is PTHREAD_MUTEX_RECURSIVE,
     20  * then the mutex maintains the concept of a lock count.
     21  * When a thread successfully acquires a mutex for the first time,
     22  * the lock count is set to one. Every time a thread relocks this mutex,
     23  * the lock count is incremented by one.
     24  * Each time the thread unlocks the mutex,
     25  * the lock count is decremented by one.
     26  * When the lock count reaches zero,
     27  * the mutex becomes available and others threads can acquire it.
     28 
     29  * The steps are:
     30  * ->Create a mutex with recursive attribute
     31  * ->Create a threads
     32  * ->Parent locks the mutex twice, unlocks once.
     33  * ->Child attempts to lock the mutex.
     34  * ->Parent unlocks the mutex.
     35  * ->Parent unlocks the mutex (shall fail)
     36  * ->Child unlocks the mutex.
     37  */
     38 
     39  /*
     40   * - adam.li (at) intel.com 2004-05-13
     41   *   Add to PTS. Please refer to http://nptl.bullopensource.org/phpBB/
     42   *   for general information
     43   */
     44 
     45   /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
     46 #define _POSIX_C_SOURCE 200112L
     47 
     48  /* We need the setrlimit() function from X/OPEN standard */
     49 #ifndef WITHOUT_XOPEN
     50 #define _XOPEN_SOURCE	600
     51 
     52 /********************************************************************************************/
     53 /****************************** standard includes *****************************************/
     54 /********************************************************************************************/
     55 #include <pthread.h>
     56 #include <unistd.h>
     57 #include <stdio.h>
     58 #include <stdlib.h>
     59 #include <stdarg.h>
     60 #include <semaphore.h>		/* for synchronization */
     61 #include <errno.h>
     62 
     63 /********************************************************************************************/
     64 /******************************   Test framework   *****************************************/
     65 /********************************************************************************************/
     66 #include "../testfrmw/testfrmw.h"
     67 #include "../testfrmw/testfrmw.c"
     68  /* This header is responsible for defining the following macros:
     69   * UNRESOLVED(ret, descr);
     70   *    where descr is a description of the error and ret is an int (error code for example)
     71   * FAILED(descr);
     72   *    where descr is a short text saying why the test has failed.
     73   * PASSED();
     74   *    No parameter.
     75   *
     76   * Both three macros shall terminate the calling process.
     77   * The testcase shall not terminate in any other maneer.
     78   *
     79   * The other file defines the functions
     80   * void output_init()
     81   * void output(char * string, ...)
     82   *
     83   * Those may be used to output information.
     84   */
     85 
     86 /********************************************************************************************/
     87 /********************************** Configuration ******************************************/
     88 /********************************************************************************************/
     89 #ifndef VERBOSE
     90 #define VERBOSE 1
     91 #endif
     92 
     93 /********************************************************************************************/
     94 /***********************************    Test case   *****************************************/
     95 /********************************************************************************************/
     96 pthread_mutex_t mtx;
     97 sem_t sem;
     98 
     99 /** child thread function **/
    100 void *threaded(void *arg)
    101 {
    102 	int ret;
    103 	/* Try to lock the mutex once. The call must fail here. */
    104 	ret = pthread_mutex_trylock(&mtx);
    105 	if (ret == 0) {
    106 		FAILED("Child first trylock succeeded");
    107 	}
    108 #if VERBOSE >1
    109 	output("[thrd] Try to lock the mutex.... failed (normal)\n");
    110 #endif
    111 
    112 	/* Free the parent thread and lock the mutex (must success) */
    113 	if ((ret = sem_post(&sem))) {
    114 		UNRESOLVED(errno, "1st post sem in child failed");
    115 	}
    116 
    117 	if ((ret = pthread_mutex_lock(&mtx))) {
    118 		UNRESOLVED(ret, "Child lock failed");
    119 	}
    120 #if VERBOSE >1
    121 	output("[thrd] Successfully locked the mutex\n");
    122 #endif
    123 
    124 	/* Wait for the parent to let us go on */
    125 	if ((ret = sem_post(&sem))) {
    126 		UNRESOLVED(errno, "2nd post sem in child failed");
    127 	}
    128 
    129 	/* Unlock and exit */
    130 	if ((ret = pthread_mutex_unlock(&mtx))) {
    131 		UNRESOLVED(ret, "Unlock in child failed");
    132 	}
    133 #if VERBOSE >1
    134 	output("[thrd] Unlocked the mutex, ready to terminate.\n");
    135 #endif
    136 
    137 	return NULL;
    138 }
    139 
    140 /** parent thread function **/
    141 int main(void)
    142 {
    143 	int ret;
    144 	int i;
    145 	pthread_mutexattr_t ma;
    146 	pthread_t child;
    147 
    148 	output_init();
    149 
    150 #if VERBOSE >1
    151 	output("Initialize the PTHREAD_MUTEX_RECURSIVE mutex\n");
    152 #endif
    153 
    154 	/* Initialize the semaphore */
    155 	if ((ret = sem_init(&sem, 0, 0))) {
    156 		UNRESOLVED(ret, "Sem init failed");
    157 	}
    158 
    159 	/* We initialize the recursive mutex */
    160 	if ((ret = pthread_mutexattr_init(&ma))) {
    161 		UNRESOLVED(ret, "Mutex attribute init failed");
    162 	}
    163 
    164 	if ((ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE))) {
    165 		UNRESOLVED(ret, "Set type RECURSIVE failed");
    166 	}
    167 
    168 	if ((ret = pthread_mutex_init(&mtx, &ma))) {
    169 		UNRESOLVED(ret, "Recursive mutex init failed");
    170 	}
    171 
    172 	if ((ret = pthread_mutexattr_destroy(&ma))) {
    173 		UNRESOLVED(ret, "Mutex attribute destroy failed");
    174 	}
    175 
    176 	/* -- The mutex is now ready for testing -- */
    177 
    178 	/* First, we lock it twice and unlock once */
    179 	if ((ret = pthread_mutex_lock(&mtx))) {
    180 		UNRESOLVED(ret, "First lock failed");
    181 	}
    182 
    183 	if ((ret = pthread_mutex_lock(&mtx))) {
    184 		FAILED("Second lock failed");
    185 	}
    186 
    187 	if ((ret = pthread_mutex_unlock(&mtx))) {
    188 		FAILED("First unlock failed");
    189 	}
    190 #if VERBOSE >1
    191 	output
    192 	    ("The mutex has been locked twice and unlocked once, start the thread now.\n");
    193 #endif
    194 
    195 	/* Here this thread owns the mutex and the internal count is "1" */
    196 
    197 	/* We create the child thread */
    198 	if ((ret = pthread_create(&child, NULL, threaded, NULL))) {
    199 		UNRESOLVED(ret, "Unable to create child thread");
    200 	}
    201 
    202 	/* then wait for child to be ready */
    203 	if ((ret = sem_wait(&sem))) {
    204 		UNRESOLVED(errno, "Wait sem in child failed");
    205 	}
    206 #if VERBOSE >1
    207 	output("[main] unlock the mutex.\n");
    208 #endif
    209 
    210 	/* We can now unlock the mutex */
    211 	if ((ret = pthread_mutex_unlock(&mtx))) {
    212 		FAILED("Second unlock failed");
    213 	}
    214 
    215 	/* We wait for the child to lock the mutex */
    216 	if ((ret = sem_wait(&sem))) {
    217 		UNRESOLVED(errno, "Wait sem in child failed");
    218 	}
    219 
    220 	/* Then, try to unlock the mutex (owned by the child or unlocked) */
    221 	ret = pthread_mutex_unlock(&mtx);
    222 	if (ret == 0) {
    223 		FAILED("Unlock of unowned mutex succeeds");
    224 	}
    225 
    226 	/* Everything seems OK here */
    227 	if ((ret = pthread_join(child, NULL))) {
    228 		UNRESOLVED(ret, "Child join failed");
    229 	}
    230 
    231 	/* Simple loop to double-check */
    232 #if VERBOSE >1
    233 	output("[main] joined the thread.\n");
    234 	output("Lock & unlock the mutex 50 times.\n");
    235 #endif
    236 
    237 	for (i = 0; i < 50; i++) {
    238 		if ((ret = pthread_mutex_lock(&mtx))) {
    239 			FAILED("Lock failed in loop");
    240 		}
    241 	}
    242 	for (i = 0; i < 50; i++) {
    243 		if ((ret = pthread_mutex_unlock(&mtx))) {
    244 			FAILED("Unlock failed in loop");
    245 		}
    246 	}
    247 
    248 	ret = pthread_mutex_unlock(&mtx);
    249 	if (ret == 0) {
    250 		FAILED("Unlock succeeds after the loop");
    251 	}
    252 #if VERBOSE >1
    253 	output("Everything went OK; destroy the mutex.\n");
    254 #endif
    255 	/* The test passed, we destroy the mutex */
    256 	if ((ret = pthread_mutex_destroy(&mtx))) {
    257 		UNRESOLVED(ret, "Final mutex destroy failed");
    258 	}
    259 
    260 	PASSED;
    261 }
    262 #else /* WITHOUT_XOPEN */
    263 int main(void)
    264 {
    265 	output_init();
    266 	UNTESTED("This test requires XSI features");
    267 }
    268 #endif
    269