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 file is a scalability test for the pthread_mutex_init function.
     19 
     20  * The steps are:
     21  * -> Restrict the memory to 32Mb * SCALABILITY_FACTOR
     22  * -> While there is free memory
     23  *      -> allocate memory for 10 mutex
     24  *      -> time = 0
     25  *      -> init the 10 mutex with different attributes
     26  *      -> output time
     27  * -> When memory is full; undo everything:
     28  *      -> time=0
     29  *      -> destroy the 10 mutexes
     30  *      -> output time
     31  *      -> free memory
     32  * -> We could additionally lock each mutex after init, and unlock before destroy.
     33  */
     34 
     35  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
     36 #define _POSIX_C_SOURCE 200112L
     37 
     38  /* We enable the following line to have mutex attributes defined */
     39 #ifndef WITHOUT_XOPEN
     40 #define _XOPEN_SOURCE	600
     41 
     42 /********************************************************************************************/
     43 /****************************** standard includes *****************************************/
     44 /********************************************************************************************/
     45 #include <pthread.h>
     46 #include <errno.h>
     47 #include <unistd.h>
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <stdarg.h>
     51 #include <sys/resource.h>
     52 #include <sys/time.h>
     53 
     54 /********************************************************************************************/
     55 /******************************   Test framework   *****************************************/
     56 /********************************************************************************************/
     57 #include "testfrmw.h"
     58 #include "testfrmw.c"
     59  /* This header is responsible for defining the following macros:
     60   * UNRESOLVED(ret, descr);
     61   *    where descr is a description of the error and ret is an int (error code for example)
     62   * FAILED(descr);
     63   *    where descr is a short text saying why the test has failed.
     64   * PASSED();
     65   *    No parameter.
     66   *
     67   * Both three macros shall terminate the calling process.
     68   * The testcase shall not terminate in any other maneer.
     69   *
     70   * The other file defines the functions
     71   * void output_init()
     72   * void output(char * string, ...)
     73   *
     74   * Those may be used to output information.
     75   */
     76 
     77 /********************************************************************************************/
     78 /********************************** Configuration ******************************************/
     79 /********************************************************************************************/
     80 #ifndef SCALABILITY_FACTOR
     81 #define SCALABILITY_FACTOR 1
     82 #endif
     83 #ifndef VERBOSE
     84 #define VERBOSE 1
     85 #endif
     86 
     87 #define WITH_LOCKS
     88 
     89 /********************************************************************************************/
     90 /***********************************    Test case   *****************************************/
     91 /********************************************************************************************/
     92 
     93 typedef struct _teststruct {
     94 	pthread_mutex_t mtx[10 * SCALABILITY_FACTOR];
     95 	pthread_mutexattr_t ma[5];
     96 	pthread_mutexattr_t *pma[10 * SCALABILITY_FACTOR];
     97 	struct _teststruct *prev;
     98 } teststruct_t;
     99 
    100 int types[] = { PTHREAD_MUTEX_NORMAL,
    101 	PTHREAD_MUTEX_ERRORCHECK,
    102 	PTHREAD_MUTEX_RECURSIVE,
    103 	PTHREAD_MUTEX_DEFAULT
    104 };
    105 
    106 int main(int argc, char *argv[])
    107 {
    108 	struct rlimit rl;
    109 	int ret;
    110 	int i;
    111 	teststruct_t *cur, *prev;
    112 	struct timeval time_zero, time_cour, time_res, time_sav[8];
    113 	long sav = 0;
    114 
    115 	/* Limit the process memory to a small value (64Mb for example). */
    116 	rl.rlim_max = 1024 * 1024 * 32 * SCALABILITY_FACTOR;
    117 	rl.rlim_cur = rl.rlim_max;
    118 	if ((ret = setrlimit(RLIMIT_AS, &rl))) {
    119 		UNRESOLVED(ret, "Memory limitation failed");
    120 	}
    121 #if VERBOSE > 1
    122 	output(";Memory is now limited to %dMb\n", rl.rlim_max >> 20);
    123 #endif
    124 
    125 	prev = NULL;
    126 	cur = NULL;
    127 
    128 	/* Loop while we have memory left */
    129 	while (1) {
    130 		/* Allocate memory for 10 mutex and related stuff */
    131 		cur = malloc(sizeof(teststruct_t));
    132 		if (cur == NULL)	/* No memory left */
    133 			break;
    134 
    135 		/* Link to the previous so we are able to free memory */
    136 		cur->prev = prev;
    137 		prev = cur;
    138 
    139 		/* Initialize the mutex attributes */
    140 		/* We will have:
    141 		 * pma[0] = NULL
    142 		 * pma[1] = NORMAL type mutex attribute
    143 		 * pma[2] = RECURSIVE type mutex attribute
    144 		 * pma[3] = ERRORCHECK type mutex attribute
    145 		 * pma[4] = DEFAULT type mutex attribute
    146 		 * pma[5] = default mutex attribute
    147 		 * pma[6] = NORMAL type mutex attribute
    148 		 * pma[7] = RECURSIVE type mutex attribute
    149 		 * pma[8] = ERRORCHECK type mutex attribute
    150 		 * pma[9] = DEFAULT type mutex attribute
    151 		 * pma[10] = pma[5] ...
    152 		 */
    153 		for (i = 0; i < 5; i++) {
    154 			if ((ret = pthread_mutexattr_init(&(cur->ma[i])))) {
    155 				UNRESOLVED(ret, "Mutex attribute init failed");
    156 			}
    157 			if (i) {
    158 				if ((ret =
    159 				     pthread_mutexattr_settype(&(cur->ma[i]),
    160 							       types[i - 1]))) {
    161 					UNRESOLVED(ret, "Mutex settype failed");
    162 				}
    163 			}
    164 		}
    165 		cur->pma[0] = NULL;
    166 		for (i = 1; i < (10 * SCALABILITY_FACTOR); i++) {
    167 			cur->pma[i] = &(cur->ma[i % 5]);
    168 		}		/* The mutex attributes are now initialized */
    169 
    170 		/* Save the time */
    171 		gettimeofday(&time_zero, NULL);
    172 
    173 		/* For each mutex, we will:
    174 		 * - init the mutex
    175 		 * - destroy the mutex
    176 		 * - init the mutex
    177 		 * - lock the mutex
    178 		 * - unlock the mutex
    179 		 * if WITH_LOCKS,
    180 		 * - lock the mutex
    181 		 */
    182 		for (i = 0; i < 10 * SCALABILITY_FACTOR; i++) {
    183 			ret = pthread_mutex_init(&(cur->mtx[i]), cur->pma[i]);
    184 			if (ret) {
    185 				UNRESOLVED(ret, "Mutex 1st init failed");
    186 			}
    187 			ret = pthread_mutex_destroy(&(cur->mtx[i]));
    188 			if (ret) {
    189 				UNRESOLVED(ret, "Mutex 1st destroy failed");
    190 			}
    191 			ret = pthread_mutex_init(&(cur->mtx[i]), cur->pma[i]);
    192 			if (ret) {
    193 				UNRESOLVED(ret, "Mutex 2nd init failed");
    194 			}
    195 			ret = pthread_mutex_lock(&(cur->mtx[i]));
    196 			if (ret) {
    197 				UNRESOLVED(ret, "Mutex 1st lock failed");
    198 			}
    199 			ret = pthread_mutex_unlock(&(cur->mtx[i]));
    200 			if (ret) {
    201 				UNRESOLVED(ret, "Mutex 1st unlock failed");
    202 			}
    203 #ifdef WITH_LOCKS
    204 			ret = pthread_mutex_lock(&(cur->mtx[i]));
    205 			if (ret) {
    206 				UNRESOLVED(ret, "Mutex 2st lock failed");
    207 			}
    208 #endif
    209 		}
    210 		/* Compute the operation duration */
    211 		gettimeofday(&time_cour, NULL);
    212 		time_res.tv_usec =
    213 		    time_cour.tv_usec + 1000000 - time_zero.tv_usec;
    214 		if (time_res.tv_usec < 1000000) {
    215 			time_res.tv_sec =
    216 			    time_cour.tv_sec - 1 - time_zero.tv_sec;
    217 		} else {
    218 			time_res.tv_sec = time_cour.tv_sec - time_zero.tv_sec;
    219 			time_res.tv_usec -= 1000000;
    220 		}
    221 
    222 		if (sav > 3) {
    223 			time_sav[4].tv_sec = time_sav[5].tv_sec;
    224 			time_sav[4].tv_usec = time_sav[5].tv_usec;
    225 			time_sav[5].tv_sec = time_sav[6].tv_sec;
    226 			time_sav[5].tv_usec = time_sav[6].tv_usec;
    227 			time_sav[6].tv_sec = time_sav[7].tv_sec;
    228 			time_sav[6].tv_usec = time_sav[7].tv_usec;
    229 			time_sav[7].tv_sec = time_res.tv_sec;
    230 			time_sav[7].tv_usec = time_res.tv_usec;
    231 		} else {
    232 			time_sav[sav].tv_sec = time_res.tv_sec;
    233 			time_sav[sav].tv_usec = time_res.tv_usec;
    234 		}
    235 		sav++;
    236 #if VERBOSE > 2
    237 		output("%4i.%06i;\n", time_res.tv_sec, time_res.tv_usec);
    238 #endif
    239 	}
    240 	if (errno != ENOMEM) {
    241 		UNRESOLVED(errno, "Memory not full");
    242 	}
    243 
    244 	/* Now we just have to cleanup everything. */
    245 	while (prev != NULL) {
    246 		cur = prev;
    247 		prev = cur->prev;
    248 
    249 		/* Free the mutex resources in the cur element */
    250 		for (i = 0; i < 10 * SCALABILITY_FACTOR; i++) {
    251 #ifdef WITH_LOCKS
    252 			ret = pthread_mutex_unlock(&(cur->mtx[i]));
    253 			if (ret) {
    254 				UNRESOLVED(ret, "Mutex 2nd unlock failed");
    255 			}
    256 #endif
    257 			ret = pthread_mutex_destroy(&(cur->mtx[i]));
    258 			if (ret) {
    259 				UNRESOLVED(ret, "Mutex 2nd destroy failed");
    260 			}
    261 		}
    262 		/* Free the mutex attributes resources in the cur element */
    263 		for (i = 0; i < 5; i++) {
    264 			if ((ret = pthread_mutexattr_destroy(&(cur->ma[i])))) {
    265 				UNRESOLVED(ret,
    266 					   "Mutex attribute destroy failed");
    267 			}
    268 		}
    269 		/* Free the element memory */
    270 		free(cur);
    271 	}
    272 #if VERBOSE > 0
    273 	if (sav < 8) {
    274 		output("Not enough iterations to build statistics\n");
    275 	} else {
    276 		output("Duration for the operations:\n");
    277 		output(" %8i : %2i.%06i s\n", 0, time_sav[0].tv_sec,
    278 		       time_sav[0].tv_usec);
    279 		output(" %8i : %2i.%06i s\n", 1, time_sav[1].tv_sec,
    280 		       time_sav[1].tv_usec);
    281 		output(" %8i : %2i.%06i s\n", 2, time_sav[2].tv_sec,
    282 		       time_sav[2].tv_usec);
    283 		output(" %8i : %2i.%06i s\n", 3, time_sav[3].tv_sec,
    284 		       time_sav[3].tv_usec);
    285 		output(" [...]\n");
    286 		output(" %8i : %2i.%06i s\n", sav - 3, time_sav[4].tv_sec,
    287 		       time_sav[4].tv_usec);
    288 		output(" %8i : %2i.%06i s\n", sav - 2, time_sav[5].tv_sec,
    289 		       time_sav[5].tv_usec);
    290 		output(" %8i : %2i.%06i s\n", sav - 1, time_sav[6].tv_sec,
    291 		       time_sav[6].tv_usec);
    292 		output(" %8i : %2i.%06i s\n", sav, time_sav[7].tv_sec,
    293 		       time_sav[7].tv_usec);
    294 	}
    295 #endif
    296 
    297 	PASSED;
    298 }
    299 
    300 #else /* WITHOUT_XOPEN */
    301 int main(int argc, char *argv[])
    302 {
    303 	output_init();
    304 	UNRESOLVED(0, "This test requires XSI features");
    305 }
    306 #endif
    307