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