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 * -> pthread_self() returns the thread ID of the calling thread. 19 * Therefore, it never returns the same value for 2 different running threads. 20 21 * The steps are: 22 * -> Create some threads with different parameters 23 * -> Get the threads IDs 24 * -> Compare all the threads IDs to find duplicates. 25 26 */ 27 28 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 29 #define _POSIX_C_SOURCE 200112L 30 31 /* Some routines are part of the XSI Extensions */ 32 #ifndef WITHOUT_XOPEN 33 #define _XOPEN_SOURCE 600 34 #endif 35 /********************************************************************************************/ 36 /****************************** standard includes *****************************************/ 37 /********************************************************************************************/ 38 #include <pthread.h> 39 #include <stdarg.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include <semaphore.h> 46 #include <errno.h> 47 #include <signal.h> 48 49 /********************************************************************************************/ 50 /****************************** Test framework *****************************************/ 51 /********************************************************************************************/ 52 #include "testfrmw.h" 53 #include "testfrmw.c" 54 /* This header is responsible for defining the following macros: 55 * UNRESOLVED(ret, descr); 56 * where descr is a description of the error and ret is an int (error code for example) 57 * FAILED(descr); 58 * where descr is a short text saying why the test has failed. 59 * PASSED(); 60 * No parameter. 61 * 62 * Both three macros shall terminate the calling process. 63 * The testcase shall not terminate in any other maneer. 64 * 65 * The other file defines the functions 66 * void output_init() 67 * void output(char * string, ...) 68 * 69 * Those may be used to output information. 70 */ 71 72 /********************************************************************************************/ 73 /********************************** Configuration ******************************************/ 74 /********************************************************************************************/ 75 #ifndef VERBOSE 76 #define VERBOSE 1 77 #endif 78 79 /********************************************************************************************/ 80 /*********************************** Test cases *****************************************/ 81 /********************************************************************************************/ 82 83 #include "threads_scenarii.c" 84 85 /* This file will define the following objects: 86 * scenarii: array of struct __scenario type. 87 * NSCENAR : macro giving the total # of scenarii 88 * scenar_init(): function to call before use the scenarii array. 89 * scenar_fini(): function to call after end of use of the scenarii array. 90 */ 91 92 /********************************************************************************************/ 93 /*********************************** Real Test *****************************************/ 94 /********************************************************************************************/ 95 96 char do_it = 1; 97 long long iterations = 0; 98 99 /* Handler for user request to terminate */ 100 void sighdl(int sig) 101 { 102 /* do_it = 0 */ 103 do { 104 do_it = 0; 105 } 106 while (do_it); 107 } 108 109 /* Protect concurrent access to the shared data */ 110 pthread_mutex_t m_synchro = PTHREAD_MUTEX_INITIALIZER; 111 112 /* Signaled when all threads are running */ 113 pthread_cond_t c_synchro = PTHREAD_COND_INITIALIZER; 114 int c_boolean; 115 116 /* Thread ID returned by pthread_self */ 117 pthread_t running[NSCENAR]; 118 119 /* Thread function */ 120 void *threaded(void *arg) 121 { 122 int ret = 0; 123 int me = *(int *)arg; 124 125 #if VERBOSE > 6 126 output("[child%d] starting\n", me); 127 #endif 128 /* Wait for all threads being created */ 129 ret = pthread_mutex_lock(&m_synchro); 130 if (ret != 0) { 131 UNRESOLVED(ret, "Mutex lock failed"); 132 } 133 #if VERBOSE > 6 134 output("[child%d] got mutex\n", me); 135 #endif 136 137 running[me] = pthread_self(); 138 139 /* Signal we're running */ 140 do { 141 ret = sem_post(&scenarii[me].sem); 142 } 143 while ((ret == -1) && (errno == EINTR)); 144 if (ret == -1) { 145 UNRESOLVED(errno, "Failed to post the semaphore"); 146 } 147 #if VERBOSE > 6 148 output("[child%d] posted semaphore %p\n", me, &scenarii[me].sem); 149 #endif 150 151 while (!c_boolean) { 152 ret = pthread_cond_wait(&c_synchro, &m_synchro); 153 if (ret != 0) { 154 UNRESOLVED(ret, "Failed to wait the condvar"); 155 } 156 #if VERBOSE > 6 157 output("[child%d] awaken\n", me); 158 #endif 159 } 160 161 ret = pthread_mutex_unlock(&m_synchro); 162 if (ret != 0) { 163 UNRESOLVED(ret, "Mutex unlock failed"); 164 } 165 #if VERBOSE > 6 166 output("[child%d] exiting\n", me); 167 #endif 168 169 return arg; 170 } 171 172 /* Main function */ 173 int main(int argc, char *argv[]) 174 { 175 int ret = 0; 176 struct sigaction sa; 177 178 pthread_t creation[NSCENAR]; /* Thread ID returned in pthread_create */ 179 int status[NSCENAR]; /* Status of thread creation */ 180 int ids[NSCENAR]; 181 182 int i; 183 184 for (sc = 0; sc < NSCENAR; sc++) 185 ids[sc] = sc; 186 187 /* Initialize output routine */ 188 output_init(); 189 190 /* Initialize thread attribute objects */ 191 scenar_init(); 192 193 /* Register the signal handler for SIGUSR1 */ 194 sigemptyset(&sa.sa_mask); 195 sa.sa_flags = 0; 196 sa.sa_handler = sighdl; 197 if ((ret = sigaction(SIGUSR1, &sa, NULL))) { 198 UNRESOLVED(ret, "Unable to register signal handler"); 199 } 200 if ((ret = sigaction(SIGALRM, &sa, NULL))) { 201 UNRESOLVED(ret, "Unable to register signal handler"); 202 } 203 #if VERBOSE > 1 204 output("[parent] Signal handler registered\n"); 205 #endif 206 207 while (do_it) { 208 /* Initialize the shared data */ 209 c_boolean = 0; 210 211 /* Create all the threads */ 212 for (sc = 0; sc < NSCENAR; sc++) { 213 /* Create the thread */ 214 status[sc] = 215 pthread_create(&creation[sc], &scenarii[sc].ta, 216 threaded, &ids[sc]); 217 218 /* Check creation status */ 219 switch (scenarii[sc].result) { 220 case 0: /* Operation was expected to succeed */ 221 if (status[sc] != 0) { 222 UNRESOLVED(ret, 223 "Failed to create this thread"); 224 } 225 break; 226 227 case 1: /* Operation was expected to fail */ 228 if (status[sc] == 0) { 229 UNRESOLVED(-1, 230 "An error was expected but the thread creation succeeded"); 231 } 232 break; 233 234 case 2: /* We did not know the expected result */ 235 default: 236 /* Nothing */ 237 ; 238 } 239 } 240 #if VERBOSE > 6 241 output("[parent] threads created\n"); 242 #endif 243 244 /* Now wait that all threads are running */ 245 for (sc = 0; sc < NSCENAR; sc++) { 246 if (status[sc] == 0) { /* The new thread is running */ 247 #if VERBOSE > 6 248 output("[parent] Waiting for thread %d: %p\n", 249 sc, &scenarii[sc].sem); 250 #endif 251 do { 252 ret = sem_wait(&scenarii[sc].sem); 253 } 254 while ((ret == -1) && (errno == EINTR)); 255 if (ret == -1) { 256 UNRESOLVED(errno, 257 "Failed to wait for the semaphore"); 258 } 259 } 260 } 261 262 #if VERBOSE > 6 263 output("[parent] Locking the mutex\n"); 264 #endif 265 266 ret = pthread_mutex_lock(&m_synchro); 267 if (ret != 0) { 268 UNRESOLVED(ret, "Mutex lock failed"); 269 } 270 271 /* Now, we've got all shared data set, so we can seek for duplicates */ 272 for (sc = 0; sc < NSCENAR; sc++) { 273 if (status[sc] != 0) /* The new thread is running */ 274 continue; 275 276 if (pthread_equal(creation[sc], running[sc]) == 0) { 277 output("pthread_create returned an ID of %p\n", 278 creation[sc]); 279 output 280 ("pthread_self in the thread returned %p\n", 281 running[sc]); 282 FAILED("Error: Values mismatch"); 283 } 284 285 for (i = sc + 1; i < NSCENAR; i++) { 286 if (status[i] != 0) 287 continue; 288 289 if (pthread_equal(creation[sc], creation[i])) { 290 FAILED 291 ("Two different running threads have the same ID"); 292 } 293 } 294 } 295 #if VERBOSE > 6 296 output("[parent] No duplicate found\n"); 297 #endif 298 299 /* We're done, we can terminate the threads */ 300 c_boolean = 1; 301 ret = pthread_mutex_unlock(&m_synchro); 302 if (ret != 0) { 303 UNRESOLVED(ret, "Mutex unlock failed"); 304 } 305 306 ret = pthread_cond_broadcast(&c_synchro); 307 if (ret != 0) { 308 UNRESOLVED(ret, "Failed to broadcast the cond"); 309 } 310 #if VERBOSE > 6 311 output("[parent] Cond broadcasted\n"); 312 #endif 313 314 /* Join the joinable threads */ 315 for (sc = 0; sc < NSCENAR; sc++) { 316 if (status[sc] != 0) /* The new thread is running */ 317 continue; 318 319 if (scenarii[sc].detached == 0) { 320 #if VERBOSE > 6 321 output("[parent] Joining %d\n", sc); 322 #endif 323 ret = pthread_join(creation[sc], NULL); 324 if (ret != 0) { 325 UNRESOLVED(ret, 326 "Unalbe to join a thread"); 327 } 328 #if VERBOSE > 6 329 output("[parent] Joined %d\n", sc); 330 #endif 331 } 332 333 } 334 iterations++; 335 } 336 337 /* We've been asked to stop */ 338 339 scenar_fini(); 340 341 output("pthread_exit stress test PASSED -- %llu iterations\n", 342 iterations); 343 344 PASSED; 345 } 346