Home | History | Annotate | Download | only in pthread_once
      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 stress test aims to test the following assertion:
     18 
     19 *  The init_routine from pthread_once never execute
     20 * more or less than once.
     21 
     22 * The steps are:
     23 * -> Create several threads
     24 * -> All threads call pthread_once at the same time
     25 * -> Check the init_routine executed once.
     26 
     27 */
     28 
     29 /********************************************************************************************/
     30 /****************************** standard includes *****************************************/
     31 /********************************************************************************************/
     32 #include <pthread.h>
     33 #include <stdarg.h>
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <unistd.h>
     38 
     39 #include <errno.h>
     40 #include <signal.h>
     41 
     42 /********************************************************************************************/
     43 /******************************   Test framework   *****************************************/
     44 /********************************************************************************************/
     45 #include "testfrmw.h"
     46 #include "testfrmw.c"
     47 /* This header is responsible for defining the following macros:
     48  * UNRESOLVED(ret, descr);
     49  *    where descr is a description of the error and ret is an int (error code for example)
     50  * FAILED(descr);
     51  *    where descr is a short text saying why the test has failed.
     52  * PASSED();
     53  *    No parameter.
     54  *
     55  * Both three macros shall terminate the calling process.
     56  * The testcase shall not terminate in any other maneer.
     57  *
     58  * The other file defines the functions
     59  * void output_init()
     60  * void output(char * string, ...)
     61  *
     62  * Those may be used to output information.
     63  */
     64 
     65 /********************************************************************************************/
     66 /********************************** Configuration ******************************************/
     67 /********************************************************************************************/
     68 #ifndef VERBOSE
     69 #define VERBOSE 1
     70 #endif
     71 
     72 #define NTHREADS 30
     73 
     74 /********************************************************************************************/
     75 /***********************************    Test cases  *****************************************/
     76 /********************************************************************************************/
     77 
     78 char do_it = 1;
     79 long long iterations = 0;
     80 
     81 /* Handler for user request to terminate */
     82 void sighdl(int sig)
     83 {
     84 	do {
     85 		do_it = 0;
     86 	}
     87 	while (do_it);
     88 }
     89 
     90 pthread_once_t once_ctl;
     91 int once_chk;
     92 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
     93 
     94 void init_routine(void)
     95 {
     96 	int ret = 0;
     97 	ret = pthread_mutex_lock(&mtx);
     98 
     99 	if (ret != 0) {
    100 		UNRESOLVED(ret, "Failed to lock mutex in initializer");
    101 	}
    102 
    103 	once_chk++;
    104 
    105 	ret = pthread_mutex_unlock(&mtx);
    106 
    107 	if (ret != 0) {
    108 		UNRESOLVED(ret, "Failed to unlock mutex in initializer");
    109 	}
    110 
    111 	return;
    112 }
    113 
    114 /* Thread function */
    115 void *threaded(void *arg)
    116 {
    117 	int ret = 0;
    118 
    119 	/* Wait for all threads being created */
    120 	ret = pthread_barrier_wait(arg);
    121 
    122 	if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) {
    123 		UNRESOLVED(ret, "Barrier wait failed");
    124 	}
    125 
    126 	/* Call init routine */
    127 	ret = pthread_once(&once_ctl, init_routine);
    128 
    129 	if (ret != 0) {
    130 		UNRESOLVED(ret, "pthread_once failed");
    131 	}
    132 
    133 	return NULL;
    134 }
    135 
    136 /* Main function */
    137 int main(int argc, char *argv[])
    138 {
    139 	int ret = 0, i;
    140 
    141 	struct sigaction sa;
    142 
    143 	pthread_barrier_t bar;
    144 
    145 	pthread_t th[NTHREADS];
    146 
    147 	/* Initialize output routine */
    148 	output_init();
    149 
    150 	/* Initialize barrier */
    151 	ret = pthread_barrier_init(&bar, NULL, NTHREADS);
    152 
    153 	if (ret != 0) {
    154 		UNRESOLVED(ret, "Failed to init barrier");
    155 	}
    156 
    157 	/* Register the signal handler for SIGUSR1 */
    158 	sigemptyset(&sa.sa_mask);
    159 
    160 	sa.sa_flags = 0;
    161 
    162 	sa.sa_handler = sighdl;
    163 
    164 	if ((ret = sigaction(SIGUSR1, &sa, NULL))) {
    165 		UNRESOLVED(ret, "Unable to register signal handler");
    166 	}
    167 
    168 	if ((ret = sigaction(SIGALRM, &sa, NULL))) {
    169 		UNRESOLVED(ret, "Unable to register signal handler");
    170 	}
    171 #if VERBOSE > 1
    172 	output("[parent] Signal handler registered\n");
    173 
    174 #endif
    175 
    176 	while (do_it) {
    177 		/* Reinitialize once handler & check value */
    178 		once_ctl = PTHREAD_ONCE_INIT;
    179 		once_chk = 0;
    180 
    181 		/* create the threads */
    182 
    183 		for (i = 0; i < NTHREADS; i++) {
    184 			ret = pthread_create(&th[i], NULL, threaded, &bar);
    185 
    186 			if (ret != 0) {
    187 				UNRESOLVED(ret, "Failed to create a thread");
    188 			}
    189 		}
    190 
    191 		/* Then join */
    192 		for (i = 0; i < NTHREADS; i++) {
    193 			ret = pthread_join(th[i], NULL);
    194 
    195 			if (ret != 0) {
    196 				UNRESOLVED(ret, "Failed to join a thread");
    197 			}
    198 		}
    199 
    200 		/* check the value */
    201 		ret = pthread_mutex_lock(&mtx);
    202 
    203 		if (ret != 0) {
    204 			UNRESOLVED(ret, "Failed to lock mutex in initializer");
    205 		}
    206 
    207 		if (once_chk != 1) {
    208 			output("Control: %d\n", once_chk);
    209 			FAILED("The initializer function did not execute once");
    210 		}
    211 
    212 		ret = pthread_mutex_unlock(&mtx);
    213 
    214 		if (ret != 0) {
    215 			UNRESOLVED(ret,
    216 				   "Failed to unlock mutex in initializer");
    217 		}
    218 
    219 		iterations++;
    220 	}
    221 
    222 	/* We've been asked to stop */
    223 
    224 	output("pthread_once stress test PASSED -- %llu iterations\n",
    225 	       iterations);
    226 
    227 	ret = pthread_barrier_destroy(&bar);
    228 
    229 	if (ret != 0) {
    230 		UNRESOLVED(ret, "Failed to destroy the barrier");
    231 	}
    232 
    233 	PASSED;
    234 }
    235