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 
     18  * This file is a scalability test for the pthread_mutex_lock function.
     19  * The goal is to test if there is a limit on the number
     20  *  of threads waiting on the same mutex.
     21 
     22  * The steps are:
     23  * -> Create 5 mutex with different attributes.
     24  * -> lock the 5 mutex in the main thread
     25  * -> Create the maximum amount of threads allowed on the system.
     26  * -> each thread, for each mutex:
     27  *       - locks the mutex
     28  *       - increments a counter
     29  *       - unlocks the mutex
     30  *       - if the counter equals the amount of threads,
     31  */
     32 
     33 /********************************************************************************************/
     34 /****************************** standard includes *****************************************/
     35 /********************************************************************************************/
     36 #include <pthread.h>
     37 #include <errno.h>
     38 #include <unistd.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <stdarg.h>
     42 
     43 /********************************************************************************************/
     44 /******************************   Test framework   *****************************************/
     45 /********************************************************************************************/
     46 #include "testfrmw.h"
     47 #include "testfrmw.c"
     48  /* This header is responsible for defining the following macros:
     49   * UNRESOLVED(ret, descr);
     50   *    where descr is a description of the error and ret is an int (error code for example)
     51   * FAILED(descr);
     52   *    where descr is a short text saying why the test has failed.
     53   * PASSED();
     54   *    No parameter.
     55   *
     56   * Both three macros shall terminate the calling process.
     57   * The testcase shall not terminate in any other maneer.
     58   *
     59   * The other file defines the functions
     60   * void output_init()
     61   * void output(char * string, ...)
     62   *
     63   * Those may be used to output information.
     64   */
     65 
     66 /********************************************************************************************/
     67 /********************************** Configuration ******************************************/
     68 /********************************************************************************************/
     69 #ifndef SCALABILITY_FACTOR
     70 #define SCALABILITY_FACTOR 1	/* This is not used in this testcase */
     71 #endif
     72 #ifndef VERBOSE
     73 #define VERBOSE 2
     74 #endif
     75 
     76 /********************************************************************************************/
     77 /***********************************    Test case   *****************************************/
     78 /********************************************************************************************/
     79 
     80 #ifndef WITHOUT_XOPEN
     81 int types[] = {
     82 	PTHREAD_MUTEX_NORMAL,
     83 	PTHREAD_MUTEX_ERRORCHECK,
     84 	PTHREAD_MUTEX_RECURSIVE,
     85 	PTHREAD_MUTEX_DEFAULT
     86 };
     87 #endif
     88 
     89 /* The mutex the threads will block on */
     90 pthread_mutex_t mtx[5];
     91 
     92 /* The condition used to signal the main thread to go to the next step */
     93 pthread_cond_t cnd;
     94 pthread_mutex_t m;
     95 
     96 /* The shared data used to control the results of the test */
     97 unsigned long nbthOK[5];
     98 unsigned long nbthNOK[5];
     99 unsigned long nbthTOT;
    100 
    101 /*****
    102  *
    103  */
    104 void *threaded(void *arg)
    105 {
    106 	int ret;
    107 	int i;
    108 	int bool;
    109 
    110 	for (i = 0; i < 5; i++) {
    111 		ret = pthread_mutex_lock(&mtx[i]);
    112 		if (ret == 0) {	/* The thread was blocked successfuly */
    113 			/* We increment nbth[i] */
    114 			ret = pthread_mutex_lock(&m);
    115 			if (ret != 0) {
    116 				UNRESOLVED(ret, "Unable to lock 'm'");
    117 			}
    118 			nbthOK[i]++;
    119 			bool = ((nbthOK[i] + nbthNOK[i]) >= nbthTOT);
    120 			ret = pthread_mutex_unlock(&m);
    121 			if (ret != 0) {
    122 				UNRESOLVED(ret, "Unable to unlock 'm'");
    123 			}
    124 
    125 			/* We can unlock the test mutex */
    126 			ret = pthread_mutex_unlock(&mtx[i]);
    127 			if (ret != 0) {
    128 				FAILED("Unlocking a test mutex failed");
    129 			}
    130 		} else {	/* Locking the test mutex failed */
    131 
    132 			/* We increment nbth[i] */
    133 			ret = pthread_mutex_lock(&m);
    134 			if (ret != 0) {
    135 				UNRESOLVED(ret, "Unable to lock 'm'");
    136 			}
    137 			nbthNOK[i]++;
    138 			bool = ((nbthOK[i] + nbthNOK[i]) >= nbthTOT);
    139 			ret = pthread_mutex_unlock(&m);
    140 			if (ret != 0) {
    141 				UNRESOLVED(ret, "Unable to unlock 'm'");
    142 			}
    143 		}
    144 
    145 		/* When every thread has passed the lock call, bool is true.
    146 		   we signal the main thread to release the next mutex. */
    147 
    148 		if (bool) {
    149 			ret = pthread_cond_signal(&cnd);
    150 			if (ret != 0) {
    151 				UNRESOLVED(ret,
    152 					   "Signaling the condition failed");
    153 			}
    154 		}
    155 	}
    156 
    157 	/* The test is terminated, the thread can die */
    158 	ret = pthread_detach(pthread_self());
    159 	if (ret != 0) {
    160 		UNRESOLVED(ret, "Thread detach failed");
    161 	}
    162 
    163 	return NULL;
    164 }
    165 
    166 int main(int argc, char *argv[])
    167 {
    168 	pthread_t th;
    169 	pthread_attr_t tha;
    170 	pthread_mutexattr_t ma;
    171 	int ret;
    172 	int i;
    173 
    174 	output_init();
    175 
    176 #if VERBOSE > 1
    177 	output("Test starting, initializing data\n");
    178 #endif
    179 
    180 	/* Init the shared data */
    181 	for (i = 0; i < 4; i++) {
    182 		nbthOK[i] = 0;
    183 		nbthNOK[i] = 0;
    184 	}
    185 	nbthTOT = 0;
    186 
    187 	/* Init the cnd */
    188 	ret = pthread_mutex_init(&m, NULL);
    189 	if (ret != 0) {
    190 		UNRESOLVED(ret, "Unable to initialize 'm'");
    191 	}
    192 	ret = pthread_cond_init(&cnd, NULL);
    193 	if (ret != 0) {
    194 		UNRESOLVED(ret, "Unable to initialize 'cnd'");
    195 	}
    196 
    197 	/* Init the 5 mutexes */
    198 	ret = pthread_mutexattr_init(&ma);
    199 	if (ret != 0) {
    200 		UNRESOLVED(ret, "Unable to initialize 'ma'");
    201 	}
    202 
    203 	for (i = 0; i < 5; i++) {
    204 #ifndef WITHOUT_XOPEN
    205 		if (i > 0) {
    206 			ret = pthread_mutexattr_settype(&ma, types[i - 1]);
    207 			if (ret != 0) {
    208 				UNRESOLVED(ret,
    209 					   "Unable to set mutex attribute type");
    210 			}
    211 		}
    212 #endif
    213 		ret = pthread_mutex_init(&mtx[i], &ma);
    214 		if (ret != 0) {
    215 			UNRESOLVED(ret, "A mutex init failed");
    216 		}
    217 	}
    218 
    219 	ret = pthread_mutexattr_destroy(&ma);
    220 	if (ret != 0) {
    221 		UNRESOLVED(ret, "Unable to destroy the mutex attribute object");
    222 	}
    223 
    224 	/* Lock the mutexes */
    225 	for (i = 0; i < 5; i++) {
    226 		ret = pthread_mutex_lock(&mtx[i]);
    227 		if (ret != 0) {
    228 			UNRESOLVED(ret,
    229 				   "Unable to lock a mutex for the first time");
    230 		}
    231 	}
    232 
    233 	/* Init the threads attribute */
    234 	ret = pthread_attr_init(&tha);
    235 	if (ret != 0) {
    236 		UNRESOLVED(ret, "Thread attribute init failed");
    237 	}
    238 
    239 	ret = pthread_attr_setstacksize(&tha, sysconf(_SC_THREAD_STACK_MIN));
    240 	if (ret != 0) {
    241 		UNRESOLVED(ret, "Unable to set stack size to minimum value");
    242 	}
    243 
    244 	/* Create as many threads as possible */
    245 #if VERBOSE > 1
    246 	output("Creating threads...\n");
    247 #endif
    248 	do {
    249 		ret = pthread_create(&th, &tha, threaded, NULL);
    250 		if (ret == 0)
    251 			nbthTOT++;
    252 	} while (ret == 0);
    253 
    254 #if VERBOSE > 1
    255 	output("Created %d threads.\n", nbthTOT);
    256 #endif
    257 
    258 	/* lock m */
    259 	ret = pthread_mutex_lock(&m);
    260 	if (ret != 0) {
    261 		UNRESOLVED(ret, "Unable to lock 'm' in main thread");
    262 	}
    263 
    264 	/* For each mutex */
    265 	for (i = 0; i < 5; i++) {
    266 		/* Yield to let other threads enter the lock function */
    267 		sched_yield();
    268 
    269 		/* unlock the test mutex */
    270 		ret = pthread_mutex_unlock(&mtx[i]);
    271 		if (ret != 0) {
    272 			UNRESOLVED(ret,
    273 				   "Unable to unlock a test mutex in main thread");
    274 		}
    275 
    276 		/* wait for cnd */
    277 		do {
    278 			ret = pthread_cond_wait(&cnd, &m);
    279 		}
    280 		while ((ret == 0) && ((nbthOK[i] + nbthNOK[i]) < nbthTOT));
    281 		if (ret != 0) {
    282 			UNRESOLVED(ret, "Unable to wait for 'cnd'");
    283 		}
    284 	}
    285 
    286 	/* unlock m */
    287 	ret = pthread_mutex_unlock(&m);
    288 	if (ret != 0) {
    289 		UNRESOLVED(ret, "Final 'm' unlock failed");
    290 	}
    291 
    292 	/* Destroy everything */
    293 	ret = pthread_attr_destroy(&tha);
    294 	if (ret != 0) {
    295 		UNRESOLVED(ret, "Final thread attribute destroy failed");
    296 	}
    297 
    298 	for (i = 0; i < 5; i++) {
    299 		ret = pthread_mutex_destroy(&mtx[i]);
    300 		if (ret != 0) {
    301 			UNRESOLVED(ret, "Unable to destroy a test mutex");
    302 		}
    303 	}
    304 
    305 	ret = pthread_cond_destroy(&cnd);
    306 	if (ret != 0) {
    307 		UNRESOLVED(ret, "Final cond destroy failed");
    308 	}
    309 
    310 	ret = pthread_mutex_destroy(&m);
    311 	if (ret != 0) {
    312 		UNRESOLVED(ret, "Final mutex destroy failed");
    313 	}
    314 
    315 	/* Output the results */
    316 	output("Sample results:\n");
    317 	output(" %lu threads were created\n", nbthTOT);
    318 	for (i = 0; i < 5; i++) {
    319 		output(" %lu threads have waited on mutex %i\n", nbthOK[i],
    320 		       i + 1);
    321 		output("  (and %lu threads could not wait)\n", nbthNOK[i]);
    322 		ret += nbthNOK[i];
    323 	}
    324 
    325 	/* Exit */
    326 	if (ret == 0) {
    327 		PASSED;
    328 	} else {
    329 		FAILED("There may be an issue in scalability");
    330 	}
    331 }
    332