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