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., 59 15 * Temple Place - Suite 330, Boston MA 02111-1307, USA. 16 * 17 18 19 * This file is a stress test for the pthread_mutex_lock function. 20 21 * The steps are: 22 * -> For each king of mutex, we create 10*F threads (F is a scalability factor) 23 * -> we call those threads 1 to 10. 24 * -> thread 1 sends signal USR2 to the other 9 threads (which have a handler for it) 25 * -> thread 2 to 6 are loops 26 * { 27 * mutex_lock 28 * if (ctrl) exit 29 * ctrl = 1 30 * yield 31 * ctrl= 0 32 * mutex unlock 33 * } 34 * -> thread 7 & 8 have a timedlock instead of lock 35 * -> thread 9 & 10 have a trylock instead of lock 36 * 37 * -> the whole process stop when receiving signal SIGUSR1. 38 * This goal is achieved with a "do_it" variable. 39 * 40 * NOTE: With gcc/linux, the flag "-lrt" must be specified at link time. 41 */ 42 43 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 44 #define _POSIX_C_SOURCE 200112L 45 46 /* We enable the following line to have mutex attributes defined */ 47#ifndef WITHOUT_XOPEN 48 #define _XOPEN_SOURCE 600 49#endif 50 51/********************************************************************************************/ 52/****************************** standard includes *****************************************/ 53/********************************************************************************************/ 54 #include <pthread.h> 55 #include <errno.h> 56 #include <semaphore.h> 57 #include <signal.h> 58 #include <unistd.h> 59#if _POSIX_TIMEOUTS < 0 60#error "This sample needs POSIX TIMEOUTS option support" 61#endif 62#if _POSIX_TIMEOUTS == 0 63#warning "This sample needs POSIX TIMEOUTS option support" 64#endif 65#if _POSIX_TIMERS < 0 66#error "This sample needs POSIX TIMERS option support" 67#endif 68#if _POSIX_TIMERS == 0 69#warning "This sample needs POSIX TIMERS option support" 70#endif 71 72 73 #include <stdio.h> 74 #include <stdlib.h> 75 #include <stdarg.h> 76 #include <time.h> /* required for the pthread_mutex_timedlock() function */ 77 78/********************************************************************************************/ 79/****************************** Test framework *****************************************/ 80/********************************************************************************************/ 81 #include "testfrmw.h" 82 #include "testfrmw.c" 83 /* This header is responsible for defining the following macros: 84 * UNRESOLVED(ret, descr); 85 * where descr is a description of the error and ret is an int (error code for example) 86 * FAILED(descr); 87 * where descr is a short text saying why the test has failed. 88 * PASSED(); 89 * No parameter. 90 * 91 * Both three macros shall terminate the calling process. 92 * The testcase shall not terminate in any other maneer. 93 * 94 * The other file defines the functions 95 * void output_init() 96 * void output(char * string, ...) 97 * 98 * Those may be used to output information. 99 */ 100 101/********************************************************************************************/ 102/********************************** Configuration ******************************************/ 103/********************************************************************************************/ 104#ifndef SCALABILITY_FACTOR 105#define SCALABILITY_FACTOR 1 106#endif 107#ifndef VERBOSE 108#define VERBOSE 2 109#endif 110#define N 2 /* N * 10 * 6 * SCALABILITY_FACTOR threads will be created */ 111 112/********************************************************************************************/ 113/*********************************** Test case *****************************************/ 114/********************************************************************************************/ 115char do_it=1; 116#ifndef WITHOUT_XOPEN 117int types[]={PTHREAD_MUTEX_NORMAL, 118 PTHREAD_MUTEX_ERRORCHECK, 119 PTHREAD_MUTEX_RECURSIVE, 120 PTHREAD_MUTEX_DEFAULT}; 121#endif 122 123/* The following type represents the data 124 * for one group of ten threads */ 125typedef struct 126{ 127 pthread_t threads[10]; /* The 10 threads */ 128 pthread_mutex_t mtx; /* The mutex those threads work on */ 129 char ctrl; /* The value used to check the behavior */ 130 char sigok; /* Used to tell the threads they can return */ 131 sem_t semsig; /* Semaphore for synchronizing the signal handler */ 132 int id; /* An identifier for the threads group */ 133 int tcnt; /* we need to make sure the threads are started before killing 'em */ 134 pthread_mutex_t tmtx; 135 unsigned long long sigcnt, opcnt; /* We count every iteration */ 136} cell_t; 137 138pthread_key_t _c; /* this key will always contain a pointer to the thread's cell */ 139 140/***** The next function is in charge of sending signal USR2 to 141 * all the other threads in its cell, until the end of the test. */ 142void * sigthr(void * arg) 143{ 144 int ret; 145 int i=0; 146 cell_t * c = (cell_t *)arg; 147 148 do 149 { 150 sched_yield(); 151 ret = pthread_mutex_lock(&(c->tmtx)); 152 if (ret != 0) { UNRESOLVED(ret, "Failed to lock the mutex"); } 153 i = c->tcnt; 154 ret = pthread_mutex_unlock(&(c->tmtx)); 155 if (ret != 0) { UNRESOLVED(ret, "Failed to unlock the mutex"); } 156 } while (i<9); 157 158 /* Until we must stop, do */ 159 while (do_it) 160 { 161 /* Wait for the semaphore */ 162 ret = sem_wait(&(c->semsig)); 163 if (ret != 0) 164 { UNRESOLVED(errno, "Sem wait failed in signal thread"); } 165 166 /* Kill the next thread */ 167 i %= 9; 168 ret = pthread_kill(c->threads[++i], SIGUSR2); 169 if (ret != 0) 170 { UNRESOLVED(ret, "Thread kill failed in signal thread"); } 171 172 /* Increment the signal counter */ 173 c->sigcnt++; 174 } 175 176 /* Tell the other threads they can now stop */ 177 do { c->sigok = 1; } 178 while ( c->sigok == 0 ); 179 180 return NULL; 181} 182 183/***** The next function is the signal handler 184 * for all the others threads in the cell */ 185void sighdl(int sig) 186{ 187 int ret; 188 cell_t * c = (cell_t *) pthread_getspecific(_c); 189 ret = sem_post(&(c->semsig)); 190 if (ret != 0) 191 { UNRESOLVED(errno, "Unable to post semaphore in signal handler"); } 192} 193 194/***** The next function can return only when the sigthr has terminated. 195 * This avoids the signal thread try to kill a terminated thread. */ 196void waitsigend(cell_t * c) 197{ 198 while ( c->sigok == 0 ) 199 { sched_yield(); } 200} 201 202/***** The next function aims to control that no other thread 203 * owns the mutex at the same time */ 204void control(cell_t * c, char * loc) 205{ 206 *loc++; /* change the local control value */ 207 if (c->ctrl != 0) 208 { FAILED("Got a non-zero value - two threads owns the mutex"); } 209 c->ctrl = *loc; 210 sched_yield(); 211 if (c->ctrl != *loc) 212 { FAILED("Got a different value - another thread touched protected data"); } 213 c->ctrl = 0; 214 215 /* Avoid some values for the next control */ 216 if (*loc == 120) 217 *loc = -120; 218 if (*loc == -1) 219 *loc = 1; 220} 221 222/***** The next 3 functions are the worker threads 223 */ 224void * lockthr(void * arg) 225{ 226 int ret; 227 char loc; /* Local value for control */ 228 cell_t * c = (cell_t *)arg; 229 230 /* Set the thread local data key value (used in the signal handler) */ 231 ret = pthread_setspecific(_c, arg); 232 if (ret != 0) 233 { UNRESOLVED(ret, "Unable to assign the thread-local-data key"); } 234 235 /* Signal we're started */ 236 ret = pthread_mutex_lock(&(c->tmtx)); 237 if (ret != 0) { UNRESOLVED(ret, "Failed to lock the mutex"); } 238 c->tcnt += 1; 239 ret = pthread_mutex_unlock(&(c->tmtx)); 240 if (ret != 0) { UNRESOLVED(ret, "Failed to unlock the mutex"); } 241 242 do 243 { 244 /* Lock, control, then unlock */ 245 ret = pthread_mutex_lock(&(c->mtx)); 246 if (ret != 0) 247 { UNRESOLVED(ret, "Mutex lock failed in worker thread"); } 248 249 control(c, &loc); 250 251 ret = pthread_mutex_unlock(&(c->mtx)); 252 if (ret != 0) 253 { UNRESOLVED(ret, "Mutex unlock failed in worker thread"); } 254 255 /* Increment the operation counter */ 256 c->opcnt++; 257 } 258 while (do_it); 259 260 /* Wait for the signal thread to terminate before we can exit */ 261 waitsigend(c); 262 return NULL; 263} 264 265void * timedlockthr(void * arg) 266{ 267 int ret; 268 char loc; /* Local value for control */ 269 struct timespec ts; 270 cell_t * c = (cell_t *)arg; 271 272 /* Set the thread local data key value (used in the signal handler) */ 273 ret = pthread_setspecific(_c, arg); 274 if (ret != 0) 275 { UNRESOLVED(ret, "Unable to assign the thread-local-data key"); } 276 277 /* Signal we're started */ 278 ret = pthread_mutex_lock(&(c->tmtx)); 279 if (ret != 0) { UNRESOLVED(ret, "Failed to lock the mutex"); } 280 c->tcnt += 1; 281 ret = pthread_mutex_unlock(&(c->tmtx)); 282 if (ret != 0) { UNRESOLVED(ret, "Failed to unlock the mutex"); } 283 284 do 285 { 286 /* Lock, control, then unlock */ 287 do 288 { 289 ret = clock_gettime(CLOCK_REALTIME, &ts); 290 if (ret != 0) 291 { UNRESOLVED(errno, "Unable to get time for timeout"); } 292 ts.tv_sec++; /* We will wait for 1 second */ 293 ret = pthread_mutex_timedlock(&(c->mtx), &ts); 294 } while (ret == ETIMEDOUT); 295 if (ret != 0) 296 { UNRESOLVED(ret, "Timed mutex lock failed in worker thread"); } 297 298 control(c, &loc); 299 300 ret = pthread_mutex_unlock(&(c->mtx)); 301 if (ret != 0) 302 { UNRESOLVED(ret, "Mutex unlock failed in worker thread"); } 303 304 /* Increment the operation counter */ 305 c->opcnt++; 306 } 307 while (do_it); 308 309 /* Wait for the signal thread to terminate before we can exit */ 310 waitsigend(c); 311 return NULL; 312} 313 314void * trylockthr(void * arg) 315{ 316 int ret; 317 char loc; /* Local value for control */ 318 cell_t * c = (cell_t *)arg; 319 320 /* Set the thread local data key value (used in the signal handler) */ 321 ret = pthread_setspecific(_c, arg); 322 if (ret != 0) 323 { UNRESOLVED(ret, "Unable to assign the thread-local-data key"); } 324 325 /* Signal we're started */ 326 ret = pthread_mutex_lock(&(c->tmtx)); 327 if (ret != 0) { UNRESOLVED(ret, "Failed to lock the mutex"); } 328 c->tcnt += 1; 329 ret = pthread_mutex_unlock(&(c->tmtx)); 330 if (ret != 0) { UNRESOLVED(ret, "Failed to unlock the mutex"); } 331 332 do 333 { 334 /* Lock, control, then unlock */ 335 do 336 { 337 ret = pthread_mutex_trylock(&(c->mtx)); 338 } while (ret == EBUSY); 339 if (ret != 0) 340 { UNRESOLVED(ret, "Mutex lock try failed in worker thread"); } 341 342 control(c, &loc); 343 344 ret = pthread_mutex_unlock(&(c->mtx)); 345 if (ret != 0) 346 { UNRESOLVED(ret, "Mutex unlock failed in worker thread"); } 347 348 /* Increment the operation counter */ 349 c->opcnt++; 350 } 351 while (do_it); 352 353 /* Wait for the signal thread to terminate before we can exit */ 354 waitsigend(c); 355 return NULL; 356} 357 358/***** The next function initializes a cell_t object 359 * This includes running the threads */ 360void cell_init(int id, cell_t * c, pthread_mutexattr_t *pma) 361{ 362 int ret, i; 363 pthread_attr_t pa; /* We will specify a minimal stack size */ 364 365 /* mark this group with its ID */ 366 c->id = id; 367 /* Initialize some other values */ 368 c->sigok = 0; 369 c->ctrl = 0; 370 c->sigcnt = 0; 371 c->opcnt = 0; 372 c->tcnt = 0; 373 374 /* Initialize the mutex */ 375 ret = pthread_mutex_init(&(c->tmtx), NULL); 376 if (ret != 0) 377 { UNRESOLVED(ret, "Mutex init failed"); } 378 ret = pthread_mutex_init(&(c->mtx), pma); 379 if (ret != 0) 380 { UNRESOLVED(ret, "Mutex init failed"); } 381 #if VERBOSE > 1 382 output("Mutex initialized in cell %i\n", id); 383 #endif 384 385 /* Initialize the semaphore */ 386 ret = sem_init(&(c->semsig), 0, 0); 387 if (ret != 0) 388 { UNRESOLVED(errno, "Sem init failed"); } 389 #if VERBOSE > 1 390 output("Semaphore initialized in cell %i\n", id); 391 #endif 392 393 /* Create the thread attribute with the minimal size */ 394 ret = pthread_attr_init(&pa); 395 if (ret != 0) 396 { UNRESOLVED(ret, "Unable to create pthread attribute object"); } 397 ret = pthread_attr_setstacksize(&pa, sysconf(_SC_THREAD_STACK_MIN)); 398 if (ret != 0) 399 { UNRESOLVED(ret, "Unable to specify minimal stack size"); } 400 401 402 /* Create the signal thread */ 403 ret = pthread_create(&(c->threads[0]), &pa, sigthr, (void *) c); 404 if (ret != 0) 405 { UNRESOLVED(ret, "Unable to create the signal thread"); } 406 407 /* Create 5 "lock" threads */ 408 for (i=1; i<=5; i++) 409 { 410 ret = pthread_create(&(c->threads[i]), &pa, lockthr, (void *) c); 411 if (ret != 0) 412 { UNRESOLVED(ret, "Unable to create a locker thread"); } 413 } 414 415 /* Create 2 "timedlock" threads */ 416 for (i=6; i<=7; i++) 417 { 418 ret = pthread_create(&(c->threads[i]), &pa, timedlockthr, (void *) c); 419 if (ret != 0) 420 { UNRESOLVED(ret, "Unable to create a (timed) locker thread"); } 421 } 422 423 /* Create 2 "trylock" threads */ 424 for (i=8; i<=9; i++) 425 { 426 ret = pthread_create(&(c->threads[i]), &pa, trylockthr, (void *) c); 427 if (ret != 0) 428 { UNRESOLVED(ret, "Unable to create a (try) locker thread"); } 429 } 430 431 #if VERBOSE > 1 432 output("All threads initialized in cell %i\n", id); 433 #endif 434 435 /* Destroy the thread attribute object */ 436 ret = pthread_attr_destroy(&pa); 437 if (ret != 0) 438 { UNRESOLVED(ret, "Unable to destroy thread attribute object"); } 439 440 /* Tell the signal thread to start working */ 441 ret = sem_post(&(c->semsig)); 442 if (ret != 0) 443 { UNRESOLVED(ret, "Unable to post signal semaphore"); } 444} 445 446/***** The next function destroys a cell_t object 447 * This includes stopping the threads */ 448void cell_fini( 449 int id, 450 cell_t * c, 451 unsigned long long * globalopcount, 452 unsigned long long * globalsigcount ) 453{ 454 int ret, i; 455 456 /* Just a basic check */ 457 if (id != c->id) 458 { 459 output("Something is wrong: Cell %i has id %i\n", id, c->id); 460 FAILED("Some memory has been corrupted"); 461 } 462 463 /* Start with joining the threads */ 464 for (i=0; i<10; i++) 465 { 466 ret = pthread_join(c->threads[i], NULL); 467 if (ret != 0) 468 { UNRESOLVED(ret, "Unable to join a thread"); } 469 } 470 471 /* Destroy the semaphore and the mutex */ 472 ret = sem_destroy(&(c->semsig)); 473 if (ret != 0) 474 { UNRESOLVED(errno, "Unable to destroy the semaphore"); } 475 476 ret = pthread_mutex_destroy(&(c->mtx)); 477 if (ret != 0) 478 { 479 output("Unable to destroy the mutex in cell %i (ret = %i)\n", id, ret); 480 FAILED("Mutex destruction failed"); 481 } 482 483 /* Report the cell counters */ 484 *globalopcount += c->opcnt; 485 *globalsigcount += c->sigcnt; 486 #if VERBOSE > 1 487 output("Counters for cell %i:\n\t%llu locks and unlocks\n\t%llu signals\n", 488 id, 489 c->opcnt, 490 c->sigcnt); 491 #endif 492 493 /* We are done with this cell. */ 494} 495 496 497/**** Next function is called when the process is killed with SIGUSR1 498 * It tells every threads in every cells to stop their work. 499 */ 500void globalsig(int sig) 501{ 502 output("Signal received, processing. Please wait...\n"); 503 do { do_it=0; } 504 while (do_it); 505} 506 507 508/****** 509 * Last but not least, the main function 510 */ 511int main(int argc, char * argv[]) 512{ 513 /* Main is responsible for : 514 * the mutex attributes initializing 515 * the creation of the cells 516 * the destruction of everything on SIGUSR1 reception 517 */ 518 519 int ret; 520 int i; 521 struct sigaction sa; 522 unsigned long long globopcnt=0, globsigcnt=0; 523 524 #ifndef WITHOUT_XOPEN 525 int sz = 2 + (sizeof(types) / sizeof(int)); 526 #else 527 int sz = 2; 528 #endif 529 pthread_mutexattr_t ma[sz-1]; 530 pthread_mutexattr_t *pma[sz]; 531 532 cell_t data[sz * N * SCALABILITY_FACTOR]; 533 534 pma[sz-1] = NULL; 535 536 #if VERBOSE > 0 537 output("Mutex lock / unlock stress sample is starting\n"); 538 output("Kill with SIGUSR1 to stop the process\n"); 539 output("\t kill -USR1 <pid>\n\n"); 540 #endif 541 542 /* Initialize the mutex attributes */ 543 for (i=0; i<sz-1; i++) 544 { 545 pma[i] = &ma[i]; 546 ret = pthread_mutexattr_init(pma[i]); 547 if (ret != 0) 548 { UNRESOLVED(ret, "Unable to init a mutex attribute object"); } 549 #ifndef WITHOUT_XOPEN /* we have the mutex attribute types */ 550 if (i != 0) 551 { 552 ret = pthread_mutexattr_settype(pma[i], types[i-1]); 553 if (ret != 0) 554 { 555 UNRESOLVED(ret, "Unable to set type of a mutex attribute object"); 556 } 557 } 558 #endif 559 } 560 #if VERBOSE > 1 561 output("%i mutex attribute objects were initialized\n", sz - 1); 562 #endif 563 564 /* Initialize the thread-local-data key */ 565 ret = pthread_key_create(&_c, NULL); 566 if (ret != 0) 567 { UNRESOLVED(ret, "Unable to initialize TLD key"); } 568 #if VERBOSE > 1 569 output("TLD key initialized\n"); 570 #endif 571 572 /* Register the signal handler for SIGUSR1 */ 573 sigemptyset (&sa.sa_mask); 574 sa.sa_flags = 0; 575 sa.sa_handler = globalsig; 576 if ((ret = sigaction (SIGUSR1, &sa, NULL))) 577 { UNRESOLVED(ret, "Unable to register signal handler"); } 578 579 /* Register the signal handler for SIGUSR2 */ 580 sa.sa_handler = sighdl; 581 if ((ret = sigaction (SIGUSR2, &sa, NULL))) 582 { UNRESOLVED(ret, "Unable to register signal handler"); } 583 584 /* Start every threads */ 585 #if VERBOSE > 0 586 output("%i cells of 10 threads are being created...\n", sz * N * SCALABILITY_FACTOR); 587 #endif 588 for (i=0; i< sz * N * SCALABILITY_FACTOR; i++) 589 cell_init(i, &data[i], pma[i % sz]); 590 #if VERBOSE > 0 591 output("All threads created and running.\n"); 592 #endif 593 594 /* We stay here while not interrupted */ 595 do { sched_yield(); } 596 while (do_it); 597 598 #if VERBOSE > 0 599 output("Starting to join the threads...\n"); 600 #endif 601 /* Everybody is stopping, we must join them, and destroy the cell data */ 602 for (i=0; i< sz * N * SCALABILITY_FACTOR; i++) 603 cell_fini(i, &data[i], &globopcnt, &globsigcnt); 604 605 /* Destroy the mutex attributes objects */ 606 for (i=0; i<sz-1; i++) 607 { 608 ret = pthread_mutexattr_destroy(pma[i]); 609 if (ret != 0) 610 { UNRESOLVED(ret, "Unable to destroy a mutex attribute object"); } 611 } 612 613 /* Destroy the thread-local-data key */ 614 ret = pthread_key_delete(_c); 615 if (ret != 0) 616 { UNRESOLVED(ret, "Unable to destroy TLD key"); } 617 #if VERBOSE > 1 618 output("TLD key destroyed\n"); 619 #endif 620 621 /* output the total counters */ 622 #if VERBOSE > 1 623 output("===============================================\n"); 624 #endif 625 #if VERBOSE > 0 626 output("Total counters:\n\t%llu locks and unlocks\n\t%llu signals\n", 627 globopcnt, 628 globsigcnt); 629 output("pthread_mutex_lock stress test passed.\n"); 630 #endif 631 632 PASSED; 633} 634