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 file is a stress test for the pthread_mutex_trylock function. 18 * 19 * It aims to check that when EBUSY is returned, the mutex has not been locked. 20 21 * The steps are: 22 * -> do 23 * -> Set up a timeout. The test fails if this timeout expires. 24 * -> lock the mutex 25 * -> create N threads. 26 * -> each thread loops on pthread_mutex_trylock while ret == EBUSY and go_on is true.. 27 * -> if ret == 0 && go_on is true, wait on a barrier then go_on = 0. 28 * -> if ret == 0 unlock the mutex 29 * -> do 30 * -> unlock the mutex 31 * -> yield 32 * -> trylock the mutex 33 * -> while we don't get EBUSY. 34 * -> wait on the barrier to unblock the thread which got the 0 error code. 35 * If no thread got this code but one got the mutex, 36 * the main thread will hang here and the timeout will expire (test FAILS). 37 * -> join all the threads 38 * -> while we don't receive SIGUSR1 39 */ 40 41 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 42 #define _POSIX_C_SOURCE 200112L 43 44 /* We need the XSI extention for the mutex attributes */ 45 #ifndef WITHOUT_XOPEN 46 #define _XOPEN_SOURCE 600 47 #endif 48 /********************************************************************************************/ 49 /****************************** standard includes *****************************************/ 50 /********************************************************************************************/ 51 #include <pthread.h> 52 #include <stdarg.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <unistd.h> 56 57 #include <errno.h> 58 #include <semaphore.h> 59 #include <signal.h> 60 61 /********************************************************************************************/ 62 /****************************** Test framework *****************************************/ 63 /********************************************************************************************/ 64 #include "testfrmw.h" 65 #include "testfrmw.c" 66 /* This header is responsible for defining the following macros: 67 * UNRESOLVED(ret, descr); 68 * where descr is a description of the error and ret is an int (error code for example) 69 * FAILED(descr); 70 * where descr is a short text saying why the test has failed. 71 * PASSED(); 72 * No parameter. 73 * 74 * Both three macros shall terminate the calling process. 75 * The testcase shall not terminate in any other maneer. 76 * 77 * The other file defines the functions 78 * void output_init() 79 * void output(char * string, ...) 80 * 81 * Those may be used to output information. 82 */ 83 84 /********************************************************************************************/ 85 /********************************** Configuration ******************************************/ 86 /********************************************************************************************/ 87 #ifndef VERBOSE 88 #define VERBOSE 1 89 #endif 90 91 #ifndef SCALABILITY_FACTOR 92 #define SCALABILITY_FACTOR 1 93 #endif 94 95 #define NCHILDREN (20 * SCALABILITY_FACTOR) 96 97 #define TIMEOUT (120 * SCALABILITY_FACTOR) 98 99 /********************************************************************************************/ 100 /*********************************** Test case *****************************************/ 101 /********************************************************************************************/ 102 103 char do_it = 1; 104 105 /* Signal handler which will stop the stress run */ 106 void sighdl(int sig) 107 { 108 do { 109 do_it = 0; 110 } 111 while (do_it); 112 } 113 114 /* Timeout thread */ 115 void *timer(void *arg) 116 { 117 unsigned int to = TIMEOUT; 118 do { 119 to = sleep(to); 120 } 121 while (to > 0); 122 FAILED 123 ("Operation timed out. EBUSY was returned while a thread acquired the mutex?."); 124 return NULL; /* For compiler */ 125 } 126 127 /* Test specific data */ 128 char go_on = 0; 129 130 typedef struct { 131 pthread_mutex_t *mtx; 132 pthread_barrier_t *bar; 133 } testdata_t; 134 135 struct _scenar { 136 int m_type; /* Mutex type to use */ 137 int m_pshared; /* 0: mutex is process-private (default) ~ !0: mutex is process-shared, if supported */ 138 char *descr; /* Case description */ 139 } scenarii[] = { 140 { 141 PTHREAD_MUTEX_DEFAULT, 0, "Default mutex"} 142 #ifndef WITHOUT_XOPEN 143 , { 144 PTHREAD_MUTEX_NORMAL, 0, "Normal mutex"} 145 , { 146 PTHREAD_MUTEX_ERRORCHECK, 0, "Errorcheck mutex"} 147 , { 148 PTHREAD_MUTEX_RECURSIVE, 0, "Recursive mutex"} 149 #endif 150 151 , { 152 PTHREAD_MUTEX_DEFAULT, 1, "Pshared mutex"} 153 #ifndef WITHOUT_XOPEN 154 , { 155 PTHREAD_MUTEX_NORMAL, 1, "Pshared Normal mutex"} 156 , { 157 PTHREAD_MUTEX_ERRORCHECK, 1, "Pshared Errorcheck mutex"} 158 , { 159 PTHREAD_MUTEX_RECURSIVE, 1, "Pshared Recursive mutex"} 160 #endif 161 }; 162 163 #define NSCENAR (sizeof(scenarii)/sizeof(scenarii[0])) 164 165 void *threaded(void *arg) 166 { 167 int ret = 0, ret2 = 0; 168 testdata_t *td = (testdata_t *) arg; 169 170 /* do */ 171 do { 172 /* trylock the mutex */ 173 ret = pthread_mutex_trylock(td->mtx); 174 175 /* yield */ 176 sched_yield(); 177 178 } 179 /* while trylock returns EBUSY and go_on == 1 */ 180 while ((ret == EBUSY) && (go_on == 1)); 181 182 /* if go_on==1 and ret == 0 */ 183 if ((go_on == 1) && (ret == 0)) { 184 #if VERBOSE > 6 185 output("[child %p] I got the mutex\n", pthread_self()); 186 #endif 187 188 /* barrier */ 189 ret2 = pthread_barrier_wait(td->bar); 190 if ((ret2 != 0) && (ret2 != PTHREAD_BARRIER_SERIAL_THREAD)) { 191 UNRESOLVED(ret2, "Pthread_barrier_wait failed"); 192 } 193 194 /* go_on = 0 */ 195 go_on = 0; 196 } 197 198 /* if ret == 0 */ 199 if (ret == 0) { 200 /* Unlock the mutex */ 201 ret = pthread_mutex_unlock(td->mtx); 202 if (ret != 0) { 203 UNRESOLVED(ret, "Failed to unlock the mutex"); 204 } 205 } 206 207 /* end of thread */ 208 return NULL; 209 } 210 211 int main(int argc, char *argv[]) 212 { 213 int ret; 214 struct sigaction sa; 215 216 pthread_t t_child[NCHILDREN]; 217 218 pthread_t t_timer; 219 220 testdata_t td; 221 222 int i, ch; 223 long pshared; 224 pthread_mutex_t mtx[NSCENAR + 2]; 225 pthread_mutexattr_t ma; 226 pthread_barrier_t bar; 227 228 /* Initialize output */ 229 output_init(); 230 231 /* System abilities */ 232 pshared = sysconf(_SC_THREAD_PROCESS_SHARED); 233 234 /* Register the signal handler for SIGUSR1 */ 235 sigemptyset(&sa.sa_mask); 236 sa.sa_flags = 0; 237 sa.sa_handler = sighdl; 238 if ((ret = sigaction(SIGUSR1, &sa, NULL))) { 239 UNRESOLVED(ret, "Unable to register signal handler"); 240 } 241 if ((ret = sigaction(SIGALRM, &sa, NULL))) { 242 UNRESOLVED(ret, "Unable to register signal handler"); 243 } 244 #if VERBOSE > 1 245 output("[parent] Signal handler registered\n"); 246 #endif 247 248 /* Initialize the barrier */ 249 ret = pthread_barrier_init(&bar, NULL, 2); 250 if (ret != 0) { 251 UNRESOLVED(ret, "Barrier init failed"); 252 } 253 td.bar = &bar; 254 255 /* Initialize every mutexattr & mutex objects */ 256 for (i = 0; i < NSCENAR; i++) { 257 ret = pthread_mutexattr_init(&ma); 258 if (ret != 0) { 259 UNRESOLVED(ret, 260 "[parent] Unable to initialize the mutex attribute object"); 261 } 262 #ifndef WITHOUT_XOPEN 263 /* Set the mutex type */ 264 ret = pthread_mutexattr_settype(&ma, scenarii[i].m_type); 265 if (ret != 0) { 266 UNRESOLVED(ret, "[parent] Unable to set mutex type"); 267 } 268 #endif 269 /* Set the pshared attributes, if supported */ 270 if ((pshared > 0) && (scenarii[i].m_pshared != 0)) { 271 ret = 272 pthread_mutexattr_setpshared(&ma, 273 PTHREAD_PROCESS_SHARED); 274 if (ret != 0) { 275 UNRESOLVED(ret, 276 "[parent] Unable to set the mutex process-shared"); 277 } 278 } 279 280 /* Initialize the mutex */ 281 ret = pthread_mutex_init(&mtx[i], &ma); 282 if (ret != 0) { 283 UNRESOLVED(ret, "[parent] Mutex init failed"); 284 } 285 286 /* Destroy the ma object */ 287 ret = pthread_mutexattr_destroy(&ma); 288 if (ret != 0) { 289 UNRESOLVED(ret, 290 "Failed to destroy the mutexattr object"); 291 } 292 } 293 /* Default mutexattr object */ 294 ret = pthread_mutexattr_init(&ma); 295 if (ret != 0) { 296 UNRESOLVED(ret, 297 "[parent] Unable to initialize the mutex attribute object"); 298 } 299 ret = pthread_mutex_init(&mtx[i], &ma); 300 if (ret != 0) { 301 UNRESOLVED(ret, "[parent] Mutex init failed"); 302 } 303 ret = pthread_mutexattr_destroy(&ma); 304 if (ret != 0) { 305 UNRESOLVED(ret, "Failed to destroy the mutexattr object"); 306 } 307 /* Default mutex */ 308 ret = pthread_mutex_init(&mtx[i + 1], NULL); 309 if (ret != 0) { 310 UNRESOLVED(ret, "[parent] Mutex init failed"); 311 } 312 313 i = 0; 314 /* While we are not asked to stop */ 315 while (do_it) { 316 /* Start the timeout thread */ 317 ret = pthread_create(&t_timer, NULL, timer, NULL); 318 if (ret != 0) { 319 UNRESOLVED(ret, "Unable to create timer thread"); 320 } 321 322 /* Set the td pointer to the next mutex */ 323 td.mtx = &mtx[i]; 324 325 /* lock this mutex */ 326 ret = pthread_mutex_lock(td.mtx); 327 if (ret != 0) { 328 UNRESOLVED(ret, "Failed to lock a mutex"); 329 } 330 331 /* go_on = 1 */ 332 go_on = 1; 333 334 /* Start the children */ 335 for (ch = 0; ch < NCHILDREN; ch++) { 336 ret = pthread_create(&t_child[ch], NULL, threaded, &td); 337 if (ret != 0) { 338 UNRESOLVED(ret, 339 "Failed to create enough threads"); 340 } 341 } 342 #if VERBOSE > 5 343 output("[parent] The children are running...\n"); 344 #endif 345 346 /* do */ 347 do { 348 /* unlock the mutex */ 349 ret = pthread_mutex_unlock(td.mtx); 350 if (ret != 0) { 351 UNRESOLVED(ret, "Failed to unlcok the mutex"); 352 } 353 354 /* yield */ 355 sched_yield(); 356 357 /* trylock the mutex again */ 358 ret = pthread_mutex_trylock(td.mtx); 359 } 360 /* while trylock succeeds */ 361 while (ret == 0); 362 if (ret != EBUSY) { 363 UNRESOLVED(ret, "An unexpected error occured"); 364 } 365 #if VERBOSE > 6 366 output 367 ("[parent] Mutex is busy, a child shall be waiting on the barrier\n"); 368 #endif 369 370 /* barrier */ 371 ret = pthread_barrier_wait(&bar); 372 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { 373 UNRESOLVED(ret, "Pthread_barrier_wait failed"); 374 } 375 376 /* cancel the timeout thread */ 377 ret = pthread_cancel(t_timer); 378 if (ret != 0) { 379 UNRESOLVED(ret, "Failed to cancel the timeout thread"); 380 } 381 382 /* join every threads (incl. the timeout) */ 383 ret = pthread_join(t_timer, NULL); 384 if (ret != 0) { 385 UNRESOLVED(ret, "Failed to join timeout thread"); 386 } 387 for (ch = 0; ch < NCHILDREN; ch++) { 388 ret = pthread_join(t_child[ch], NULL); 389 if (ret != 0) { 390 UNRESOLVED(ret, "Failed to join a child"); 391 } 392 } 393 394 /* next mutex */ 395 i++; 396 i %= NSCENAR + 2; 397 } 398 399 /* destroy the barrier & mutexes objects */ 400 ret = pthread_barrier_destroy(&bar); 401 if (ret != 0) { 402 UNRESOLVED(ret, "Failed to destroy the barrier"); 403 } 404 405 for (i = 0; i < NSCENAR + 2; i++) { 406 ret = pthread_mutex_destroy(&mtx[i]); 407 if (ret != 0) { 408 UNRESOLVED(ret, "Failed to destroy a mutex"); 409 } 410 } 411 412 #if VERBOSE > 0 413 output("pthread_mutex_trylock stress test passed\n"); 414 #endif 415 416 /* test passed */ 417 PASSED; 418 } 419