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