Home | History | Annotate | Download | only in pthread_cond_destroy
      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 sample test aims to check the following assertion:
     18  *
     19  * It is safe to destroy a condition variable when no thread is blocked on it.
     20 
     21  * The steps are:
     22  *  -> Some threads are waiting on a condition variable.
     23  *  -> A thread broadcasts and destroys immediatly the condvar,
     24  *     then corrupts the memory of the condvar.
     25  *
     26  * The test fails if it hangs or if an error is returned, either
     27  * in the wait routines or in the destroy routine.
     28  *
     29  */
     30 
     31  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
     32 #define _POSIX_C_SOURCE 200112L
     33 
     34  /* We need the XSI extention for the mutex attributes */
     35 #ifndef WITHOUT_XOPEN
     36 #define _XOPEN_SOURCE	600
     37 #endif
     38 /********************************************************************************************/
     39 /****************************** standard includes *****************************************/
     40 /********************************************************************************************/
     41 #include <pthread.h>
     42 #include <stdarg.h>
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <unistd.h>
     46 
     47 #include <errno.h>
     48 #include <signal.h>
     49 #include <string.h>
     50 #include <time.h>
     51 #include <sys/mman.h>
     52 #include <sys/wait.h>
     53 
     54 /********************************************************************************************/
     55 /******************************   Test framework   *****************************************/
     56 /********************************************************************************************/
     57 #include "../testfrmw/testfrmw.h"
     58 #include "../testfrmw/testfrmw.c"
     59  /* This header is responsible for defining the following macros:
     60   * UNRESOLVED(ret, descr);
     61   *    where descr is a description of the error and ret is an int (error code for example)
     62   * FAILED(descr);
     63   *    where descr is a short text saying why the test has failed.
     64   * PASSED();
     65   *    No parameter.
     66   *
     67   * Both three macros shall terminate the calling process.
     68   * The testcase shall not terminate in any other maneer.
     69   *
     70   * The other file defines the functions
     71   * void output_init()
     72   * void output(char * string, ...)
     73   *
     74   * Those may be used to output information.
     75   */
     76 #define UNRESOLVED_KILLALL(error, text, Tchild) { \
     77 	if (td->fork) \
     78 	{ \
     79 		int _nch; \
     80 		for (_nch=0; _nch<NTHREADS; _nch++) \
     81 			kill(Tchild[_nch], SIGKILL); \
     82 	} \
     83 	UNRESOLVED(error, text); \
     84 	}
     85 #define FAILED_KILLALL(text, Tchild) { \
     86 	if (td->fork) \
     87 	{ \
     88 		int _nch; \
     89 		for (_nch=0; _nch<NTHREADS; _nch++) \
     90 			kill(Tchild[_nch], SIGKILL); \
     91 	} \
     92 	FAILED(text); \
     93 	}
     94 /********************************************************************************************/
     95 /********************************** Configuration ******************************************/
     96 /********************************************************************************************/
     97 #ifndef VERBOSE
     98 #define VERBOSE 1
     99 #endif
    100 
    101 #define NTHREADS (5)
    102 
    103 #define TIMEOUT  (120)
    104 
    105 #ifndef WITHOUT_ALTCLK
    106 #define USE_ALTCLK		/* test with MONOTONIC CLOCK if supported */
    107 #endif
    108 
    109 /********************************************************************************************/
    110 /***********************************    Test case   *****************************************/
    111 /********************************************************************************************/
    112 
    113 #ifdef WITHOUT_XOPEN
    114 /* We define those to avoid compilation errors, but they won't be used */
    115 #define PTHREAD_MUTEX_DEFAULT 0
    116 #define PTHREAD_MUTEX_NORMAL 0
    117 #define PTHREAD_MUTEX_ERRORCHECK 0
    118 #define PTHREAD_MUTEX_RECURSIVE 0
    119 
    120 #endif
    121 
    122 struct _scenar {
    123 	int m_type;		/* Mutex type to use */
    124 	int mc_pshared;		/* 0: mutex and cond are process-private (default) ~ !0: Both are process-shared, if supported */
    125 	int c_clock;		/* 0: cond uses the default clock. ~ !0: Cond uses monotonic clock, if supported. */
    126 	int fork;		/* 0: Test between threads. ~ !0: Test across processes, if supported (mmap) */
    127 	char *descr;		/* Case description */
    128 } scenarii[] = {
    129 	{
    130 	PTHREAD_MUTEX_DEFAULT, 0, 0, 0, "Default mutex"}
    131 	, {
    132 	PTHREAD_MUTEX_NORMAL, 0, 0, 0, "Normal mutex"}
    133 	, {
    134 	PTHREAD_MUTEX_ERRORCHECK, 0, 0, 0, "Errorcheck mutex"}
    135 	, {
    136 	PTHREAD_MUTEX_RECURSIVE, 0, 0, 0, "Recursive mutex"}
    137 
    138 	, {
    139 	PTHREAD_MUTEX_DEFAULT, 1, 0, 0, "PShared default mutex"}
    140 	, {
    141 	PTHREAD_MUTEX_NORMAL, 1, 0, 0, "Pshared normal mutex"}
    142 	, {
    143 	PTHREAD_MUTEX_ERRORCHECK, 1, 0, 0, "Pshared errorcheck mutex"}
    144 	, {
    145 	PTHREAD_MUTEX_RECURSIVE, 1, 0, 0, "Pshared recursive mutex"}
    146 
    147 	, {
    148 	PTHREAD_MUTEX_DEFAULT, 1, 0, 1,
    149 		    "Pshared default mutex across processes"}
    150 	, {
    151 	PTHREAD_MUTEX_NORMAL, 1, 0, 1,
    152 		    "Pshared normal mutex across processes"}
    153 	, {
    154 	PTHREAD_MUTEX_ERRORCHECK, 1, 0, 1,
    155 		    "Pshared errorcheck mutex across processes"}
    156 	, {
    157 	PTHREAD_MUTEX_RECURSIVE, 1, 0, 1,
    158 		    "Pshared recursive mutex across processes"}
    159 
    160 #ifdef USE_ALTCLK
    161 	, {
    162 	PTHREAD_MUTEX_DEFAULT, 1, 1, 1,
    163 		    "Pshared default mutex and alt clock condvar across processes"}
    164 	, {
    165 	PTHREAD_MUTEX_NORMAL, 1, 1, 1,
    166 		    "Pshared normal mutex and alt clock condvar across processes"}
    167 	, {
    168 	PTHREAD_MUTEX_ERRORCHECK, 1, 1, 1,
    169 		    "Pshared errorcheck mutex and alt clock condvar across processes"}
    170 	, {
    171 	PTHREAD_MUTEX_RECURSIVE, 1, 1, 1,
    172 		    "Pshared recursive mutex and alt clock condvar across processes"}
    173 
    174 	, {
    175 	PTHREAD_MUTEX_DEFAULT, 0, 1, 0,
    176 		    "Default mutex and alt clock condvar"}
    177 	, {
    178 	PTHREAD_MUTEX_NORMAL, 0, 1, 0,
    179 		    "Normal mutex and alt clock condvar"}
    180 	, {
    181 	PTHREAD_MUTEX_ERRORCHECK, 0, 1, 0,
    182 		    "Errorcheck mutex and alt clock condvar"}
    183 	, {
    184 	PTHREAD_MUTEX_RECURSIVE, 0, 1, 0,
    185 		    "Recursive mutex and alt clock condvar"}
    186 
    187 	, {
    188 	PTHREAD_MUTEX_DEFAULT, 1, 1, 0,
    189 		    "PShared default mutex and alt clock condvar"}
    190 	, {
    191 	PTHREAD_MUTEX_NORMAL, 1, 1, 0,
    192 		    "Pshared normal mutex and alt clock condvar"}
    193 	, {
    194 	PTHREAD_MUTEX_ERRORCHECK, 1, 1, 0,
    195 		    "Pshared errorcheck mutex and alt clock condvar"}
    196 	, {
    197 	PTHREAD_MUTEX_RECURSIVE, 1, 1, 0,
    198 		    "Pshared recursive mutex and alt clock condvar"}
    199 #endif
    200 };
    201 
    202 #define NSCENAR (sizeof(scenarii)/sizeof(scenarii[0]))
    203 
    204 /* The shared data */
    205 typedef struct {
    206 	int count1;		/* number of children currently waiting (1st pass) */
    207 	int count2;		/* number of children currently waiting (2nd pass) */
    208 	pthread_cond_t cnd;
    209 	pthread_mutex_t mtx1;
    210 	pthread_mutex_t mtx2;
    211 	int predicate1, predicate2;	/* Boolean associated to the condvar */
    212 	clockid_t cid;		/* clock used in the condvar */
    213 	char fork;		/* the children are processes */
    214 } testdata_t;
    215 testdata_t *td;
    216 
    217 /* Child function (either in a thread or in a process) */
    218 void *child(void *arg)
    219 {
    220 	int ret = 0;
    221 	struct timespec ts;
    222 	char timed;
    223 
    224 	/* lock the 1st mutex */
    225 	ret = pthread_mutex_lock(&td->mtx1);
    226 	if (ret != 0) {
    227 		UNRESOLVED(ret, "Failed to lock mutex in child");
    228 	}
    229 
    230 	/* increment count */
    231 	td->count1++;
    232 
    233 	timed = td->count1 & 1;
    234 
    235 	if (timed) {
    236 		/* get current time if we are a timedwait */
    237 		ret = clock_gettime(td->cid, &ts);
    238 		if (ret != 0) {
    239 			UNRESOLVED(errno, "Unable to read clock");
    240 		}
    241 		ts.tv_sec += TIMEOUT;
    242 	}
    243 
    244 	do {
    245 		/* Wait while the predicate is false */
    246 		if (timed)
    247 			ret = pthread_cond_timedwait(&td->cnd, &td->mtx1, &ts);
    248 		else
    249 			ret = pthread_cond_wait(&td->cnd, &td->mtx1);
    250 	} while ((ret == 0) && (td->predicate1 == 0));
    251 	if ((ret != 0) && (td->predicate1 != 0)) {
    252 		output("Wakening the cond failed with error %i (%s)\n", ret,
    253 		       strerror(ret));
    254 		FAILED
    255 		    ("Destroying the cond var while threads were awaken but inside wait routine failed.");
    256 	}
    257 	if (ret != 0) {
    258 		UNRESOLVED(ret, "Failed to wait for the cond");
    259 	}
    260 
    261 	td->count1--;
    262 
    263 	/* unlock the mutex */
    264 	ret = pthread_mutex_unlock(&td->mtx1);
    265 	if (ret != 0) {
    266 		UNRESOLVED(ret, "Failed to unlock the mutex.");
    267 	}
    268 
    269 	/* Second pass */
    270 
    271 	/* lock the mutex */
    272 	ret = pthread_mutex_lock(&td->mtx2);
    273 	if (ret != 0) {
    274 		UNRESOLVED(ret, "Failed to lock mutex in child");
    275 	}
    276 
    277 	/* increment count */
    278 	td->count2++;
    279 
    280 	timed = td->count2 & 1;
    281 
    282 	if (timed) {
    283 		/* get current time if we are a timedwait */
    284 		ret = clock_gettime(td->cid, &ts);
    285 		if (ret != 0) {
    286 			UNRESOLVED(errno, "Unable to read clock");
    287 		}
    288 		ts.tv_sec += TIMEOUT;
    289 	}
    290 
    291 	do {
    292 		/* Wait while the predicate is false */
    293 		if (timed)
    294 			ret = pthread_cond_timedwait(&td->cnd, &td->mtx2, &ts);
    295 		else
    296 			ret = pthread_cond_wait(&td->cnd, &td->mtx2);
    297 	} while ((ret == 0) && (td->predicate2 == 0));
    298 	if ((ret != 0) && (td->predicate2 != 0)) {
    299 		output("Wakening the cond failed with error %i (%s)\n", ret,
    300 		       strerror(ret));
    301 		FAILED
    302 		    ("Destroying the cond var while threads were awaken but inside wait routine failed.");
    303 	}
    304 	if (ret != 0) {
    305 		UNRESOLVED(ret, "Failed to wait for the cond");
    306 	}
    307 
    308 	/* unlock the mutex */
    309 	ret = pthread_mutex_unlock(&td->mtx2);
    310 	if (ret != 0) {
    311 		UNRESOLVED(ret, "Failed to unlock the mutex.");
    312 	}
    313 
    314 	return NULL;
    315 }
    316 
    317 /* Timeout thread */
    318 void *timer(void *arg)
    319 {
    320 	pid_t *pchildren = (pid_t *) arg;
    321 	unsigned int to = TIMEOUT;
    322 	do {
    323 		to = sleep(to);
    324 	}
    325 	while (to > 0);
    326 	FAILED_KILLALL("Test failed (hang)", pchildren);
    327 	return NULL;		/* For compiler */
    328 }
    329 
    330 /* main function */
    331 
    332 int main(void)
    333 {
    334 	int ret;
    335 
    336 	pthread_mutexattr_t ma;
    337 	pthread_condattr_t ca;
    338 
    339 	int scenar;
    340 	long pshared, monotonic, cs, mf;
    341 
    342 	pid_t p_child[NTHREADS];
    343 	pthread_t t_child[NTHREADS];
    344 	int ch;
    345 	pid_t pid;
    346 	int status;
    347 
    348 	pthread_t t_timer;
    349 
    350 	testdata_t alternativ;
    351 
    352 	output_init();
    353 
    354 	/* check the system abilities */
    355 	pshared = sysconf(_SC_THREAD_PROCESS_SHARED);
    356 	cs = sysconf(_SC_CLOCK_SELECTION);
    357 	monotonic = sysconf(_SC_MONOTONIC_CLOCK);
    358 	mf = sysconf(_SC_MAPPED_FILES);
    359 
    360 #if VERBOSE > 0
    361 	output("Test starting\n");
    362 	output("System abilities:\n");
    363 	output(" TPS : %li\n", pshared);
    364 	output(" CS  : %li\n", cs);
    365 	output(" MON : %li\n", monotonic);
    366 	output(" MF  : %li\n", mf);
    367 	if ((mf < 0) || (pshared < 0))
    368 		output("Process-shared attributes won't be tested\n");
    369 	if ((cs < 0) || (monotonic < 0))
    370 		output("Alternative clock won't be tested\n");
    371 #endif
    372 
    373 	/* We are not interested in testing the clock if we have no other clock available.. */
    374 	if (monotonic < 0)
    375 		cs = -1;
    376 
    377 #ifndef USE_ALTCLK
    378 	if (cs > 0)
    379 		output
    380 		    ("Implementation supports the MONOTONIC CLOCK but option is disabled in test.\n");
    381 #endif
    382 
    383 /**********
    384  * Allocate space for the testdata structure
    385  */
    386 	if (mf < 0) {
    387 		/* Cannot mmap a file, we use an alternative method */
    388 		td = &alternativ;
    389 		pshared = -1;	/* We won't do this testing anyway */
    390 #if VERBOSE > 0
    391 		output("Testdata allocated in the process memory.\n");
    392 #endif
    393 	} else {
    394 		/* We will place the test data in a mmaped file */
    395 		char filename[] = "/tmp/cond_destroy-XXXXXX";
    396 		size_t sz, ps;
    397 		void *mmaped;
    398 		int fd;
    399 		char *tmp;
    400 
    401 		/* We now create the temp files */
    402 		fd = mkstemp(filename);
    403 		if (fd == -1) {
    404 			UNRESOLVED(errno,
    405 				   "Temporary file could not be created");
    406 		}
    407 
    408 		/* and make sure the file will be deleted when closed */
    409 		unlink(filename);
    410 
    411 #if VERBOSE > 1
    412 		output("Temp file created (%s).\n", filename);
    413 #endif
    414 
    415 		ps = (size_t) sysconf(_SC_PAGESIZE);
    416 		sz = ((sizeof(testdata_t) / ps) + 1) * ps;	/* # pages needed to store the testdata */
    417 
    418 		tmp = calloc(1, sz);
    419 		if (tmp == NULL) {
    420 			UNRESOLVED(errno, "Memory allocation failed");
    421 		}
    422 
    423 		/* Write the data to the file.  */
    424 		if (write(fd, tmp, sz) != (ssize_t) sz) {
    425 			UNRESOLVED(sz, "Writting to the file failed");
    426 		}
    427 
    428 		free(tmp);
    429 
    430 		/* Now we can map the file in memory */
    431 		mmaped =
    432 		    mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    433 		if (mmaped == MAP_FAILED) {
    434 			UNRESOLVED(errno, "mmap failed");
    435 		}
    436 
    437 		td = (testdata_t *) mmaped;
    438 
    439 		/* Our datatest structure is now in shared memory */
    440 #if VERBOSE > 1
    441 		output("Testdata allocated in shared memory (%ib).\n",
    442 		       sizeof(testdata_t));
    443 #endif
    444 	}
    445 
    446 	/* Do the test for each test scenario */
    447 	for (scenar = 0; scenar < NSCENAR; scenar++) {
    448 		/* set / reset everything */
    449 		td->fork = 0;
    450 		ret = pthread_mutexattr_init(&ma);
    451 		if (ret != 0) {
    452 			UNRESOLVED(ret,
    453 				   "[parent] Unable to initialize the mutex attribute object");
    454 		}
    455 		ret = pthread_condattr_init(&ca);
    456 		if (ret != 0) {
    457 			UNRESOLVED(ret,
    458 				   "[parent] Unable to initialize the cond attribute object");
    459 		}
    460 #ifndef WITHOUT_XOPEN
    461 		/* Set the mutex type */
    462 		ret = pthread_mutexattr_settype(&ma, scenarii[scenar].m_type);
    463 		if (ret != 0) {
    464 			UNRESOLVED(ret, "[parent] Unable to set mutex type");
    465 		}
    466 #endif
    467 
    468 		/* Set the pshared attributes, if supported */
    469 		if ((pshared > 0) && (scenarii[scenar].mc_pshared != 0)) {
    470 			ret =
    471 			    pthread_mutexattr_setpshared(&ma,
    472 							 PTHREAD_PROCESS_SHARED);
    473 			if (ret != 0) {
    474 				UNRESOLVED(ret,
    475 					   "[parent] Unable to set the mutex process-shared");
    476 			}
    477 			ret =
    478 			    pthread_condattr_setpshared(&ca,
    479 							PTHREAD_PROCESS_SHARED);
    480 			if (ret != 0) {
    481 				UNRESOLVED(ret,
    482 					   "[parent] Unable to set the cond var process-shared");
    483 			}
    484 		}
    485 
    486 		/* Set the alternative clock, if supported */
    487 #ifdef USE_ALTCLK
    488 		if ((cs > 0) && (scenarii[scenar].c_clock != 0)) {
    489 			ret = pthread_condattr_setclock(&ca, CLOCK_MONOTONIC);
    490 			if (ret != 0) {
    491 				UNRESOLVED(ret,
    492 					   "[parent] Unable to set the monotonic clock for the cond");
    493 			}
    494 		}
    495 		ret = pthread_condattr_getclock(&ca, &td->cid);
    496 		if (ret != 0) {
    497 			UNRESOLVED(ret, "Unable to get clock from cond attr");
    498 		}
    499 #else
    500 		td->cid = CLOCK_REALTIME;
    501 #endif
    502 
    503 		/* Tell whether the test will be across processes */
    504 		if ((pshared > 0) && (scenarii[scenar].fork != 0)) {
    505 			td->fork = 1;
    506 		}
    507 
    508 		/* Proceed to testing */
    509 		/* initialize the mutex */
    510 		ret = pthread_mutex_init(&td->mtx1, &ma);
    511 		if (ret != 0) {
    512 			UNRESOLVED(ret, "Mutex init failed");
    513 		}
    514 
    515 		ret = pthread_mutex_init(&td->mtx2, &ma);
    516 		if (ret != 0) {
    517 			UNRESOLVED(ret, "Mutex init failed");
    518 		}
    519 
    520 		ret = pthread_mutex_lock(&td->mtx2);
    521 		if (ret != 0) {
    522 			UNRESOLVED(ret, "Mutex lock failed");
    523 		}
    524 
    525 		/* initialize the condvar */
    526 		ret = pthread_cond_init(&td->cnd, &ca);
    527 		if (ret != 0) {
    528 			UNRESOLVED(ret, "Cond init failed");
    529 		}
    530 #if VERBOSE > 2
    531 		output("[parent] Starting 1st pass of test %s\n",
    532 		       scenarii[scenar].descr);
    533 #endif
    534 
    535 		td->count1 = 0;
    536 		td->count2 = 0;
    537 		td->predicate1 = 0;
    538 		td->predicate2 = 0;
    539 
    540 		/* Create all the children */
    541 		for (ch = 0; ch < NTHREADS; ch++) {
    542 			if (td->fork == 0) {
    543 				ret =
    544 				    pthread_create(&t_child[ch], NULL, child,
    545 						   NULL);
    546 				if (ret != 0) {
    547 					UNRESOLVED(ret,
    548 						   "Failed to create a child thread");
    549 				}
    550 			} else {
    551 				p_child[ch] = fork();
    552 				if (p_child[ch] == -1) {
    553 					ret = errno;
    554 					for (--ch; ch >= 0; ch--)
    555 						kill(p_child[ch], SIGKILL);
    556 					UNRESOLVED(ret,
    557 						   "Failed to create a child process");
    558 				}
    559 
    560 				if (p_child[ch] == 0) {	/* We are the child */
    561 					child(NULL);
    562 					exit(0);
    563 				}
    564 			}
    565 		}
    566 #if VERBOSE > 4
    567 		output("[parent] All children are running\n");
    568 #endif
    569 
    570 		/* Make sure all children are waiting */
    571 		ret = pthread_mutex_lock(&td->mtx1);
    572 		if (ret != 0) {
    573 			UNRESOLVED_KILLALL(ret, "Failed to lock mutex",
    574 					   p_child);
    575 		}
    576 		ch = td->count1;
    577 		while (ch < NTHREADS) {
    578 			ret = pthread_mutex_unlock(&td->mtx1);
    579 			if (ret != 0) {
    580 				UNRESOLVED_KILLALL(ret,
    581 						   "Failed to unlock mutex",
    582 						   p_child);
    583 			}
    584 			sched_yield();
    585 			ret = pthread_mutex_lock(&td->mtx1);
    586 			if (ret != 0) {
    587 				UNRESOLVED_KILLALL(ret, "Failed to lock mutex",
    588 						   p_child);
    589 			}
    590 			ch = td->count1;
    591 		}
    592 
    593 #if VERBOSE > 4
    594 		output("[parent] All children are waiting\n");
    595 #endif
    596 
    597 		/* create the timeout thread */
    598 		ret = pthread_create(&t_timer, NULL, timer, p_child);
    599 		if (ret != 0) {
    600 			UNRESOLVED_KILLALL(ret, "Unable to create timer thread",
    601 					   p_child);
    602 		}
    603 
    604 		/* Wakeup the children */
    605 		td->predicate1 = 1;
    606 		ret = pthread_cond_broadcast(&td->cnd);
    607 		if (ret != 0) {
    608 			UNRESOLVED_KILLALL(ret,
    609 					   "Failed to signal the condition.",
    610 					   p_child);
    611 		}
    612 
    613 		ret = pthread_mutex_unlock(&td->mtx1);
    614 		if (ret != 0) {
    615 			UNRESOLVED_KILLALL(ret, "Failed to unlock mutex",
    616 					   p_child);
    617 		}
    618 
    619 		/* Destroy the condvar (this must be safe) */
    620 		ret = pthread_cond_destroy(&td->cnd);
    621 		if (ret != 0) {
    622 			FAILED_KILLALL
    623 			    ("Unable to destroy the cond while no thread is blocked inside",
    624 			     p_child);
    625 		}
    626 
    627 		/* Reuse the cond memory */
    628 		memset(&td->cnd, 0xFF, sizeof(pthread_cond_t));
    629 
    630 #if VERBOSE > 4
    631 		output
    632 		    ("[parent] Condition was broadcasted, and condvar destroyed.\n");
    633 #endif
    634 
    635 		/* Make sure all children have exited the first wait */
    636 		ret = pthread_mutex_lock(&td->mtx1);
    637 		if (ret != 0) {
    638 			UNRESOLVED_KILLALL(ret, "Failed to lock mutex",
    639 					   p_child);
    640 		}
    641 		ch = td->count1;
    642 		while (ch > 0) {
    643 			ret = pthread_mutex_unlock(&td->mtx1);
    644 			if (ret != 0) {
    645 				UNRESOLVED_KILLALL(ret,
    646 						   "Failed to unlock mutex",
    647 						   p_child);
    648 			}
    649 			sched_yield();
    650 			ret = pthread_mutex_lock(&td->mtx1);
    651 			if (ret != 0) {
    652 				UNRESOLVED_KILLALL(ret, "Failed to lock mutex",
    653 						   p_child);
    654 			}
    655 			ch = td->count1;
    656 		}
    657 
    658 		ret = pthread_mutex_unlock(&td->mtx1);
    659 		if (ret != 0) {
    660 			UNRESOLVED_KILLALL(ret, "Failed to unlock mutex",
    661 					   p_child);
    662 		}
    663 
    664 		/* Go toward the 2nd pass */
    665 		/* Now, all children are waiting to lock the 2nd mutex, which we own here. */
    666 		/* reinitialize the condvar */
    667 		ret = pthread_cond_init(&td->cnd, &ca);
    668 		if (ret != 0) {
    669 			UNRESOLVED(ret, "Cond init failed");
    670 		}
    671 #if VERBOSE > 2
    672 		output("[parent] Starting 2nd pass of test %s\n",
    673 		       scenarii[scenar].descr);
    674 #endif
    675 
    676 		/* Make sure all children are waiting */
    677 		ch = td->count2;
    678 		while (ch < NTHREADS) {
    679 			ret = pthread_mutex_unlock(&td->mtx2);
    680 			if (ret != 0) {
    681 				UNRESOLVED_KILLALL(ret,
    682 						   "Failed to unlock mutex",
    683 						   p_child);
    684 			}
    685 			sched_yield();
    686 			ret = pthread_mutex_lock(&td->mtx2);
    687 			if (ret != 0) {
    688 				UNRESOLVED_KILLALL(ret, "Failed to lock mutex",
    689 						   p_child);
    690 			}
    691 			ch = td->count2;
    692 		}
    693 
    694 #if VERBOSE > 4
    695 		output("[parent] All children are waiting\n");
    696 #endif
    697 
    698 		/* Wakeup the children */
    699 		td->predicate2 = 1;
    700 		ret = pthread_cond_broadcast(&td->cnd);
    701 		if (ret != 0) {
    702 			UNRESOLVED_KILLALL(ret,
    703 					   "Failed to signal the condition.",
    704 					   p_child);
    705 		}
    706 
    707 		/* Allow the children to terminate */
    708 		ret = pthread_mutex_unlock(&td->mtx2);
    709 		if (ret != 0) {
    710 			UNRESOLVED_KILLALL(ret, "Failed to unlock mutex",
    711 					   p_child);
    712 		}
    713 
    714 		/* Destroy the condvar (this must be safe) */
    715 		ret = pthread_cond_destroy(&td->cnd);
    716 		if (ret != 0) {
    717 			FAILED_KILLALL
    718 			    ("Unable to destroy the cond while no thread is blocked inside",
    719 			     p_child);
    720 		}
    721 
    722 		/* Reuse the cond memory */
    723 		memset(&td->cnd, 0x00, sizeof(pthread_cond_t));
    724 
    725 #if VERBOSE > 4
    726 		output
    727 		    ("[parent] Condition was broadcasted, and condvar destroyed.\n");
    728 #endif
    729 
    730 #if VERBOSE > 4
    731 		output("[parent] Joining the children\n");
    732 #endif
    733 
    734 		/* join the children */
    735 		for (ch = (NTHREADS - 1); ch >= 0; ch--) {
    736 			if (td->fork == 0) {
    737 				ret = pthread_join(t_child[ch], NULL);
    738 				if (ret != 0) {
    739 					UNRESOLVED(ret,
    740 						   "Failed to join a child thread");
    741 				}
    742 			} else {
    743 				pid = waitpid(p_child[ch], &status, 0);
    744 				if (pid != p_child[ch]) {
    745 					ret = errno;
    746 					output
    747 					    ("Waitpid failed (expected: %i, got: %i)\n",
    748 					     p_child[ch], pid);
    749 					for (; ch >= 0; ch--) {
    750 						kill(p_child[ch], SIGKILL);
    751 					}
    752 					UNRESOLVED(ret, "Waitpid failed");
    753 				}
    754 				if (WIFEXITED(status)) {
    755 					/* the child should return only failed or unresolved or passed */
    756 					if (ret != PTS_FAIL)
    757 						ret |= WEXITSTATUS(status);
    758 				}
    759 			}
    760 		}
    761 		if (ret != 0) {
    762 			output_fini();
    763 			exit(ret);
    764 		}
    765 #if VERBOSE > 4
    766 		output("[parent] All children terminated\n");
    767 #endif
    768 
    769 		/* cancel the timeout thread */
    770 		ret = pthread_cancel(t_timer);
    771 		if (ret != 0) {
    772 			/* Strange error here... the thread cannot be terminated (app would be killed) */
    773 			UNRESOLVED(ret, "Failed to cancel the timeout handler");
    774 		}
    775 
    776 		/* join the timeout thread */
    777 		ret = pthread_join(t_timer, NULL);
    778 		if (ret != 0) {
    779 			UNRESOLVED(ret, "Failed to join the timeout handler");
    780 		}
    781 
    782 		/* Destroy the datas */
    783 		ret = pthread_cond_destroy(&td->cnd);
    784 		if (ret != 0) {
    785 			UNRESOLVED(ret, "Failed to destroy the condvar");
    786 		}
    787 
    788 		ret = pthread_mutex_destroy(&td->mtx1);
    789 		if (ret != 0) {
    790 			UNRESOLVED(ret, "Failed to destroy the mutex");
    791 		}
    792 
    793 		ret = pthread_mutex_destroy(&td->mtx2);
    794 		if (ret != 0) {
    795 			UNRESOLVED(ret, "Failed to destroy the mutex");
    796 		}
    797 
    798 		/* Destroy the attributes */
    799 		ret = pthread_condattr_destroy(&ca);
    800 		if (ret != 0) {
    801 			UNRESOLVED(ret,
    802 				   "Failed to destroy the cond var attribute object");
    803 		}
    804 
    805 		ret = pthread_mutexattr_destroy(&ma);
    806 		if (ret != 0) {
    807 			UNRESOLVED(ret,
    808 				   "Failed to destroy the mutex attribute object");
    809 		}
    810 
    811 	}
    812 
    813 	/* exit */
    814 	PASSED;
    815 }
    816