Home | History | Annotate | Download | only in pthread_cond_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_cond_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 cond vars
     24  *      -> time = 0
     25  *      -> init the 10 cond vars with different attributes
     26  *      -> output time
     27  * -> When memory is full; undo everything:
     28  *      -> time=0
     29  *      -> destroy the 10 cond vars
     30  *      -> output time
     31  *      -> free memory
     32  */
     33 
     34  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
     35 #define _POSIX_C_SOURCE 200112L
     36 
     37  /* We need XSI conformance for memory limitation */
     38 #ifndef WITHOUT_XOPEN
     39 #define _XOPEN_SOURCE	600
     40 
     41 /********************************************************************************************/
     42 /****************************** standard includes *****************************************/
     43 /********************************************************************************************/
     44 #include <pthread.h>
     45 #include <errno.h>
     46 #include <unistd.h>
     47 #include <stdio.h>
     48 #include <stdlib.h>
     49 #include <stdarg.h>
     50 #include <sys/resource.h>
     51 #include <sys/time.h>
     52 
     53 /********************************************************************************************/
     54 /******************************   Test framework   *****************************************/
     55 /********************************************************************************************/
     56 #include "testfrmw.h"
     57 #include "testfrmw.c"
     58  /* This header is responsible for defining the following macros:
     59   * UNRESOLVED(ret, descr);
     60   *    where descr is a description of the error and ret is an int (error code for example)
     61   * FAILED(descr);
     62   *    where descr is a short text saying why the test has failed.
     63   * PASSED();
     64   *    No parameter.
     65   *
     66   * Both three macros shall terminate the calling process.
     67   * The testcase shall not terminate in any other maneer.
     68   *
     69   * The other file defines the functions
     70   * void output_init()
     71   * void output(char * string, ...)
     72   *
     73   * Those may be used to output information.
     74   */
     75 
     76 /********************************************************************************************/
     77 /********************************** Configuration ******************************************/
     78 /********************************************************************************************/
     79 #ifndef SCALABILITY_FACTOR
     80 #define SCALABILITY_FACTOR 1
     81 #endif
     82 #ifndef VERBOSE
     83 #define VERBOSE 1
     84 #endif
     85 
     86 /********************************************************************************************/
     87 /***********************************    Test case   *****************************************/
     88 /********************************************************************************************/
     89 
     90 typedef struct _teststruct {
     91 	pthread_cond_t cnd[10 * SCALABILITY_FACTOR];
     92 	pthread_condattr_t ca[4];
     93 	pthread_condattr_t *pca[10 * SCALABILITY_FACTOR];
     94 	struct _teststruct *prev;
     95 } teststruct_t;
     96 
     97 int main(int argc, char *argv[])
     98 {
     99 	struct rlimit rl;
    100 	int ret;
    101 	int i;
    102 	teststruct_t *cur, *prev;
    103 	struct timeval time_zero, time_cour, time_res, time_sav[8];
    104 	long sav = 0;
    105 
    106 	long monotonic, pshared;
    107 
    108 	pshared = sysconf(_SC_THREAD_PROCESS_SHARED);
    109 	monotonic = sysconf(_SC_MONOTONIC_CLOCK);
    110 #if VERBOSE > 1
    111 	output("Support for process-shared condvars: %li\n", pshared);
    112 	output("Support for monotonic clock        : %li\n", monotonic);
    113 #endif
    114 
    115 	/* Limit the process memory to a small value (32Mb 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 		 * pca[0] = NULL
    142 		 * pca[1] = Default cond attribute
    143 		 * pca[2] = (if supported) pshared cond attribute
    144 		 * pca[3] = (if supported) monotonic clock cond attribute
    145 		 * pca[4] = (if supported) pshared + monotonic
    146 		 * pca[5] = pca[0]...
    147 		 */
    148 		for (i = 0; i < 4; i++) {
    149 			ret = pthread_condattr_init(&(cur->ca[i]));
    150 			if (ret != 0) {
    151 				UNRESOLVED(ret, "Cond attribute init failed");
    152 			}
    153 
    154 			if ((monotonic > 0) && ((i == 2) || (i == 3))) {
    155 				ret =
    156 				    pthread_condattr_setclock(&(cur->ca[i]),
    157 							      CLOCK_MONOTONIC);
    158 				if (ret != 0) {
    159 					UNRESOLVED(ret,
    160 						   "Set monotonic clock failed");
    161 				}
    162 			}
    163 			if ((pshared > 0) && ((i == 1) || (i == 3))) {
    164 				ret =
    165 				    pthread_condattr_setpshared(&(cur->ca[i]),
    166 								PTHREAD_PROCESS_SHARED);
    167 				if (ret != 0) {
    168 					UNRESOLVED(ret,
    169 						   "Set process shared attribute failed");
    170 				}
    171 			}
    172 
    173 		}
    174 
    175 		for (i = 0; i < (10 * SCALABILITY_FACTOR); i++) {
    176 			cur->pca[i] = (i % 5) ? &(cur->ca[i % 4]) : NULL;
    177 		}		/* The mutex attributes are now initialized */
    178 
    179 		/* Save the time */
    180 		gettimeofday(&time_zero, NULL);
    181 
    182 		/* For each condvar, we will:
    183 		 * - init the condvar
    184 		 * - destroy the condvar
    185 		 * - init the condvar
    186 		 * - destroy the condvar
    187 		 * - init the condvar
    188 		 */
    189 		for (i = 0; i < 10 * SCALABILITY_FACTOR; i++) {
    190 			ret = pthread_cond_init(&(cur->cnd[i]), cur->pca[i]);
    191 			if (ret) {
    192 				UNRESOLVED(ret, "Cond 1st init failed");
    193 			}
    194 			ret = pthread_cond_destroy(&(cur->cnd[i]));
    195 			if (ret) {
    196 				UNRESOLVED(ret, "Cond 1st destroy failed");
    197 			}
    198 			ret = pthread_cond_init(&(cur->cnd[i]), cur->pca[i]);
    199 			if (ret) {
    200 				UNRESOLVED(ret, "Cond 2nd init failed");
    201 			}
    202 			ret = pthread_cond_destroy(&(cur->cnd[i]));
    203 			if (ret) {
    204 				UNRESOLVED(ret, "Cond 2nd destroy failed");
    205 			}
    206 			ret = pthread_cond_init(&(cur->cnd[i]), cur->pca[i]);
    207 			if (ret) {
    208 				UNRESOLVED(ret, "Cond 3rd init failed");
    209 			}
    210 		}
    211 		/* Compute the operation duration */
    212 		gettimeofday(&time_cour, NULL);
    213 		time_res.tv_usec =
    214 		    time_cour.tv_usec + 1000000 - time_zero.tv_usec;
    215 		if (time_res.tv_usec < 1000000) {
    216 			time_res.tv_sec =
    217 			    time_cour.tv_sec - 1 - time_zero.tv_sec;
    218 		} else {
    219 			time_res.tv_sec = time_cour.tv_sec - time_zero.tv_sec;
    220 			time_res.tv_usec -= 1000000;
    221 		}
    222 
    223 		if (sav > 3) {
    224 			time_sav[4].tv_sec = time_sav[5].tv_sec;
    225 			time_sav[4].tv_usec = time_sav[5].tv_usec;
    226 			time_sav[5].tv_sec = time_sav[6].tv_sec;
    227 			time_sav[5].tv_usec = time_sav[6].tv_usec;
    228 			time_sav[6].tv_sec = time_sav[7].tv_sec;
    229 			time_sav[6].tv_usec = time_sav[7].tv_usec;
    230 			time_sav[7].tv_sec = time_res.tv_sec;
    231 			time_sav[7].tv_usec = time_res.tv_usec;
    232 		} else {
    233 			time_sav[sav].tv_sec = time_res.tv_sec;
    234 			time_sav[sav].tv_usec = time_res.tv_usec;
    235 		}
    236 		sav++;
    237 	}
    238 	if (errno != ENOMEM) {
    239 		UNRESOLVED(errno, "Memory not full");
    240 	}
    241 
    242 	/* Now we just have to cleanup everything. */
    243 	while (prev != NULL) {
    244 		cur = prev;
    245 		prev = cur->prev;
    246 
    247 		/* Free the condvar resources in the cur element */
    248 		for (i = 0; i < 10 * SCALABILITY_FACTOR; i++) {
    249 			ret = pthread_cond_destroy(&(cur->cnd[i]));
    250 			if (ret) {
    251 				UNRESOLVED(ret, "Cond final destroy failed");
    252 			}
    253 		}
    254 		/* Free the cond attributes resources in the cur element */
    255 		for (i = 0; i < 4; i++) {
    256 			ret = pthread_condattr_destroy(&(cur->ca[i]));
    257 			if (ret != 0) {
    258 				UNRESOLVED(ret,
    259 					   "Cond attribute destroy failed");
    260 			}
    261 		}
    262 		/* Free the element memory */
    263 		free(cur);
    264 	}
    265 #if VERBOSE > 0
    266 	if (sav < 8) {
    267 		output("Not enough iterations to build statistics\n");
    268 	} else {
    269 		output("Duration for the operations:\n");
    270 		output(" %8i : %2i.%06i s\n", 0, time_sav[0].tv_sec,
    271 		       time_sav[0].tv_usec);
    272 		output(" %8i : %2i.%06i s\n", 1, time_sav[1].tv_sec,
    273 		       time_sav[1].tv_usec);
    274 		output(" %8i : %2i.%06i s\n", 2, time_sav[2].tv_sec,
    275 		       time_sav[2].tv_usec);
    276 		output(" %8i : %2i.%06i s\n", 3, time_sav[3].tv_sec,
    277 		       time_sav[3].tv_usec);
    278 		output(" [...]\n");
    279 		output(" %8i : %2i.%06i s\n", sav - 3, time_sav[4].tv_sec,
    280 		       time_sav[4].tv_usec);
    281 		output(" %8i : %2i.%06i s\n", sav - 2, time_sav[5].tv_sec,
    282 		       time_sav[5].tv_usec);
    283 		output(" %8i : %2i.%06i s\n", sav - 1, time_sav[6].tv_sec,
    284 		       time_sav[6].tv_usec);
    285 		output(" %8i : %2i.%06i s\n", sav, time_sav[7].tv_sec,
    286 		       time_sav[7].tv_usec);
    287 	}
    288 #endif
    289 
    290 	PASSED;
    291 }
    292 
    293 #else /* WITHOUT_XOPEN */
    294 int main(int argc, char *argv[])
    295 {
    296 	output_init();
    297 	UNRESOLVED(0, "This test requires XSI features");
    298 }
    299 #endif
    300