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