1 /* $NetBSD: t_cond.c,v 1.4 2013/03/17 05:13:13 jmmv Exp $ */ 2 3 /* 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __COPYRIGHT("@(#) Copyright (c) 2008\ 31 The NetBSD Foundation, inc. All rights reserved."); 32 __RCSID("$NetBSD: t_cond.c,v 1.4 2013/03/17 05:13:13 jmmv Exp $"); 33 34 #include <sys/time.h> 35 36 #include <errno.h> 37 #include <pthread.h> 38 #include <stdio.h> 39 #include <unistd.h> 40 41 #include <atf-c.h> 42 43 #include "h_common.h" 44 45 static pthread_mutex_t mutex; 46 static pthread_cond_t cond; 47 static pthread_mutex_t static_mutex = PTHREAD_MUTEX_INITIALIZER; 48 static pthread_cond_t static_cond = PTHREAD_COND_INITIALIZER; 49 static int count, share, toggle, total; 50 51 static void * 52 signal_delay_wait_threadfunc(void *arg) 53 { 54 int *shared = (int *) arg; 55 56 printf("2: Second thread.\n"); 57 58 printf("2: Locking mutex\n"); 59 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 60 printf("2: Got mutex.\n"); 61 printf("Shared value: %d. Changing to 0.\n", *shared); 62 *shared = 0; 63 64 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 65 PTHREAD_REQUIRE(pthread_cond_signal(&cond)); 66 67 return NULL; 68 } 69 70 ATF_TC(signal_delay_wait); 71 ATF_TC_HEAD(signal_delay_wait, tc) 72 { 73 atf_tc_set_md_var(tc, "descr", "Checks condition variables"); 74 } 75 ATF_TC_BODY(signal_delay_wait, tc) 76 { 77 int x; 78 pthread_t new; 79 void *joinval; 80 int sharedval; 81 82 printf("1: condition variable test 1\n"); 83 84 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); 85 PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL)); 86 87 x = 20; 88 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 89 90 sharedval = 1; 91 92 PTHREAD_REQUIRE(pthread_create(&new, NULL, signal_delay_wait_threadfunc, 93 &sharedval)); 94 95 printf("1: Before waiting.\n"); 96 do { 97 sleep(2); 98 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 99 printf("1: After waiting, in loop.\n"); 100 } while (sharedval != 0); 101 102 printf("1: After the loop.\n"); 103 104 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 105 106 printf("1: After releasing the mutex.\n"); 107 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 108 109 printf("1: Thread joined.\n"); 110 } 111 112 static void * 113 signal_before_unlock_threadfunc(void *arg) 114 { 115 int *shared = (int *) arg; 116 117 printf("2: Second thread.\n"); 118 119 printf("2: Locking mutex\n"); 120 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 121 printf("2: Got mutex.\n"); 122 printf("Shared value: %d. Changing to 0.\n", *shared); 123 *shared = 0; 124 125 /* Signal first, then unlock, for a different test than #1. */ 126 PTHREAD_REQUIRE(pthread_cond_signal(&cond)); 127 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 128 129 return NULL; 130 } 131 132 ATF_TC(signal_before_unlock); 133 ATF_TC_HEAD(signal_before_unlock, tc) 134 { 135 atf_tc_set_md_var(tc, "descr", 136 "Checks condition variables: signal before unlocking mutex"); 137 } 138 ATF_TC_BODY(signal_before_unlock, tc) 139 { 140 int x; 141 pthread_t new; 142 void *joinval; 143 int sharedval; 144 145 printf("1: condition variable test 2\n"); 146 147 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); 148 PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL)); 149 150 x = 20; 151 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 152 153 sharedval = 1; 154 155 PTHREAD_REQUIRE(pthread_create(&new, NULL, 156 signal_before_unlock_threadfunc, &sharedval)); 157 158 printf("1: Before waiting.\n"); 159 do { 160 sleep(2); 161 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 162 printf("1: After waiting, in loop.\n"); 163 } while (sharedval != 0); 164 165 printf("1: After the loop.\n"); 166 167 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 168 169 printf("1: After releasing the mutex.\n"); 170 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 171 172 printf("1: Thread joined.\n"); 173 } 174 175 static void * 176 signal_before_unlock_static_init_threadfunc(void *arg) 177 { 178 int *shared = (int *) arg; 179 180 printf("2: Second thread.\n"); 181 182 printf("2: Locking mutex\n"); 183 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 184 printf("2: Got mutex.\n"); 185 printf("Shared value: %d. Changing to 0.\n", *shared); 186 *shared = 0; 187 188 /* Signal first, then unlock, for a different test than #1. */ 189 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 190 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 191 192 return NULL; 193 } 194 195 ATF_TC(signal_before_unlock_static_init); 196 ATF_TC_HEAD(signal_before_unlock_static_init, tc) 197 { 198 atf_tc_set_md_var(tc, "descr", 199 "Checks condition variables: signal before unlocking " 200 "mutex, use static initializers"); 201 } 202 ATF_TC_BODY(signal_before_unlock_static_init, tc) 203 { 204 int x; 205 pthread_t new; 206 void *joinval; 207 int sharedval; 208 209 printf("1: condition variable test 3\n"); 210 211 x = 20; 212 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 213 214 sharedval = 1; 215 216 PTHREAD_REQUIRE(pthread_create(&new, NULL, 217 signal_before_unlock_static_init_threadfunc, &sharedval)); 218 219 printf("1: Before waiting.\n"); 220 do { 221 sleep(2); 222 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, &static_mutex)); 223 printf("1: After waiting, in loop.\n"); 224 } while (sharedval != 0); 225 226 printf("1: After the loop.\n"); 227 228 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 229 230 printf("1: After releasing the mutex.\n"); 231 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 232 233 printf("1: Thread joined.\n"); 234 } 235 236 static void * 237 signal_wait_race_threadfunc(void *arg) 238 { 239 printf("2: Second thread.\n"); 240 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 241 printf("2: Before the loop.\n"); 242 while (count>0) { 243 count--; 244 total++; 245 toggle = 0; 246 /* printf("2: Before signal %d.\n", count); */ 247 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 248 do { 249 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 250 &static_mutex)); 251 } while (toggle != 1); 252 } 253 printf("2: After the loop.\n"); 254 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 255 256 return NULL; 257 } 258 259 ATF_TC(signal_wait_race); 260 ATF_TC_HEAD(signal_wait_race, tc) 261 { 262 atf_tc_set_md_var(tc, "descr", "Checks condition variables"); 263 } 264 ATF_TC_BODY(signal_wait_race, tc) 265 { 266 pthread_t new; 267 void *joinval; 268 int sharedval; 269 270 printf("1: condition variable test 4\n"); 271 272 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 273 274 count = 50000; 275 toggle = 0; 276 277 PTHREAD_REQUIRE(pthread_create(&new, NULL, signal_wait_race_threadfunc, 278 &sharedval)); 279 280 printf("1: Before waiting.\n"); 281 while (count>0) { 282 count--; 283 total++; 284 toggle = 1; 285 /* printf("1: Before signal %d.\n", count); */ 286 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 287 do { 288 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 289 &static_mutex)); 290 } while (toggle != 0); 291 } 292 printf("1: After the loop.\n"); 293 294 toggle = 1; 295 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 296 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 297 298 printf("1: After releasing the mutex.\n"); 299 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 300 301 printf("1: Thread joined. Final count = %d, total = %d\n", 302 count, total); 303 304 ATF_REQUIRE_EQ(count, 0); 305 ATF_REQUIRE_EQ(total, 50000); 306 } 307 308 static void * 309 pthread_cond_timedwait_func(void *arg) 310 { 311 struct timespec ts; 312 size_t i = 0; 313 int rv; 314 315 for (;;) { 316 317 if (i++ >= 10000) 318 pthread_exit(NULL); 319 320 (void)memset(&ts, 0, sizeof(struct timespec)); 321 322 ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts) == 0); 323 324 /* 325 * Set to one second in the past: 326 * pthread_cond_timedwait(3) should 327 * return ETIMEDOUT immediately. 328 */ 329 ts.tv_sec = ts.tv_sec - 1; 330 331 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 332 rv = pthread_cond_timedwait(&static_cond, &static_mutex, &ts); 333 334 /* 335 * Sometimes we catch ESRCH. 336 * This should never happen. 337 */ 338 ATF_REQUIRE(rv == ETIMEDOUT); 339 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 340 } 341 } 342 343 ATF_TC(cond_timedwait_race); 344 ATF_TC_HEAD(cond_timedwait_race, tc) 345 { 346 atf_tc_set_md_var(tc, "descr", "Test pthread_cond_timedwait(3)"); 347 348 } 349 ATF_TC_BODY(cond_timedwait_race, tc) 350 { 351 pthread_t tid[64]; 352 size_t i, j; 353 354 atf_tc_expect_fail("PR lib/44756"); 355 /* This outer loop is to ensure that a false positive of this race 356 * test does not report the test as broken (due to the test not 357 * triggering the expected failure). However, we want to make this 358 * fail consistently when the race is resolved, and this approach 359 * will have the desired effect. */ 360 for (j = 0; j < 10; j++ ) { 361 for (i = 0; i < __arraycount(tid); i++) { 362 363 PTHREAD_REQUIRE(pthread_create(&tid[i], NULL, 364 pthread_cond_timedwait_func, NULL)); 365 } 366 367 for (i = 0; i < __arraycount(tid); i++) { 368 369 PTHREAD_REQUIRE(pthread_join(tid[i], NULL)); 370 } 371 } 372 } 373 374 static void * 375 broadcast_threadfunc(void *arg) 376 { 377 printf("2: Second thread.\n"); 378 379 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 380 while (count>0) { 381 count--; 382 total++; 383 toggle = 0; 384 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 385 do { 386 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 387 &static_mutex)); 388 } while (toggle != 1); 389 } 390 printf("2: After the loop.\n"); 391 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 392 393 return NULL; 394 } 395 396 397 ATF_TC(broadcast); 398 ATF_TC_HEAD(broadcast, tc) 399 { 400 atf_tc_set_md_var(tc, "descr", 401 "Checks condition variables: use pthread_cond_broadcast()"); 402 } 403 ATF_TC_BODY(broadcast, tc) 404 { 405 pthread_t new; 406 void *joinval; 407 int sharedval; 408 409 printf("1: condition variable test 5\n"); 410 411 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 412 413 count = 50000; 414 toggle = 0; 415 416 PTHREAD_REQUIRE(pthread_create(&new, NULL, broadcast_threadfunc, 417 &sharedval)); 418 419 printf("1: Before waiting.\n"); 420 while (count>0) { 421 count--; 422 total++; 423 toggle = 1; 424 PTHREAD_REQUIRE(pthread_cond_broadcast(&static_cond)); 425 do { 426 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 427 &static_mutex)); 428 } while (toggle != 0); 429 } 430 printf("1: After the loop.\n"); 431 432 toggle = 1; 433 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 434 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 435 436 printf("1: After releasing the mutex.\n"); 437 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 438 439 printf("1: Thread joined. Final count = %d, total = %d\n", count, 440 total); 441 442 ATF_REQUIRE_EQ(count, 0); 443 ATF_REQUIRE_EQ(total, 50000); 444 } 445 446 static void * 447 bogus_timedwaits_threadfunc(void *arg) 448 { 449 return NULL; 450 } 451 452 ATF_TC(bogus_timedwaits); 453 ATF_TC_HEAD(bogus_timedwaits, tc) 454 { 455 atf_tc_set_md_var(tc, "descr", 456 "Checks condition variables: bogus timedwaits"); 457 } 458 ATF_TC_BODY(bogus_timedwaits, tc) 459 { 460 pthread_t new; 461 struct timespec ts; 462 struct timeval tv; 463 464 printf("condition variable test 6: bogus timedwaits\n"); 465 466 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 467 468 printf("unthreaded test (past)\n"); 469 gettimeofday(&tv, NULL); 470 tv.tv_sec -= 2; /* Place the time in the past */ 471 TIMEVAL_TO_TIMESPEC(&tv, &ts); 472 473 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 474 &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) in the " 475 "past"); 476 477 printf("unthreaded test (zero time)\n"); 478 tv.tv_sec = 0; 479 tv.tv_usec = 0; 480 TIMEVAL_TO_TIMESPEC(&tv, &ts); 481 482 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 483 &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) with zero " 484 "time"); 485 486 PTHREAD_REQUIRE(pthread_create(&new, NULL, bogus_timedwaits_threadfunc, 487 NULL)); 488 PTHREAD_REQUIRE(pthread_join(new, NULL)); 489 490 printf("threaded test\n"); 491 gettimeofday(&tv, NULL); 492 tv.tv_sec -= 2; /* Place the time in the past */ 493 TIMEVAL_TO_TIMESPEC(&tv, &ts); 494 495 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 496 &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) in the past"); 497 498 printf("threaded test (zero time)\n"); 499 tv.tv_sec = 0; 500 tv.tv_usec = 0; 501 TIMEVAL_TO_TIMESPEC(&tv, &ts); 502 503 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 504 &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) with zero " 505 "time"); 506 507 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 508 } 509 510 static void 511 unlock(void *arg) 512 { 513 pthread_mutex_unlock((pthread_mutex_t *)arg); 514 } 515 516 static void * 517 destroy_after_cancel_threadfunc(void *arg) 518 { 519 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 520 521 pthread_cleanup_push(unlock, &mutex); 522 523 while (1) { 524 share = 1; 525 PTHREAD_REQUIRE(pthread_cond_broadcast(&cond)); 526 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 527 } 528 529 pthread_cleanup_pop(0); 530 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 531 532 return NULL; 533 } 534 535 ATF_TC(destroy_after_cancel); 536 ATF_TC_HEAD(destroy_after_cancel, tc) 537 { 538 atf_tc_set_md_var(tc, "descr", "Checks destroying a condition variable " 539 "after cancelling a wait"); 540 } 541 ATF_TC_BODY(destroy_after_cancel, tc) 542 { 543 pthread_t thread; 544 545 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); 546 PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL)); 547 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 548 PTHREAD_REQUIRE(pthread_create(&thread, NULL, 549 destroy_after_cancel_threadfunc, NULL)); 550 551 while (share == 0) { 552 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 553 } 554 555 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 556 PTHREAD_REQUIRE(pthread_cancel(thread)); 557 558 PTHREAD_REQUIRE(pthread_join(thread, NULL)); 559 PTHREAD_REQUIRE(pthread_cond_destroy(&cond)); 560 561 PTHREAD_REQUIRE(pthread_mutex_destroy(&mutex)); 562 } 563 564 ATF_TP_ADD_TCS(tp) 565 { 566 567 ATF_TP_ADD_TC(tp, signal_delay_wait); 568 ATF_TP_ADD_TC(tp, signal_before_unlock); 569 ATF_TP_ADD_TC(tp, signal_before_unlock_static_init); 570 ATF_TP_ADD_TC(tp, signal_wait_race); 571 ATF_TP_ADD_TC(tp, cond_timedwait_race); 572 ATF_TP_ADD_TC(tp, broadcast); 573 ATF_TP_ADD_TC(tp, bogus_timedwaits); 574 ATF_TP_ADD_TC(tp, destroy_after_cancel); 575 576 return atf_no_error(); 577 } 578