1 /* $NetBSD: t_cond.c,v 1.5 2013/10/19 17:45:01 christos 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.5 2013/10/19 17:45:01 christos 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 pthread_t new; 78 void *joinval; 79 int sharedval; 80 81 printf("1: condition variable test 1\n"); 82 83 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); 84 PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL)); 85 86 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 87 88 sharedval = 1; 89 90 PTHREAD_REQUIRE(pthread_create(&new, NULL, signal_delay_wait_threadfunc, 91 &sharedval)); 92 93 printf("1: Before waiting.\n"); 94 do { 95 sleep(2); 96 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 97 printf("1: After waiting, in loop.\n"); 98 } while (sharedval != 0); 99 100 printf("1: After the loop.\n"); 101 102 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 103 104 printf("1: After releasing the mutex.\n"); 105 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 106 107 printf("1: Thread joined.\n"); 108 } 109 110 static void * 111 signal_before_unlock_threadfunc(void *arg) 112 { 113 int *shared = (int *) arg; 114 115 printf("2: Second thread.\n"); 116 117 printf("2: Locking mutex\n"); 118 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 119 printf("2: Got mutex.\n"); 120 printf("Shared value: %d. Changing to 0.\n", *shared); 121 *shared = 0; 122 123 /* Signal first, then unlock, for a different test than #1. */ 124 PTHREAD_REQUIRE(pthread_cond_signal(&cond)); 125 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 126 127 return NULL; 128 } 129 130 ATF_TC(signal_before_unlock); 131 ATF_TC_HEAD(signal_before_unlock, tc) 132 { 133 atf_tc_set_md_var(tc, "descr", 134 "Checks condition variables: signal before unlocking mutex"); 135 } 136 ATF_TC_BODY(signal_before_unlock, tc) 137 { 138 pthread_t new; 139 void *joinval; 140 int sharedval; 141 142 printf("1: condition variable test 2\n"); 143 144 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); 145 PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL)); 146 147 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 148 149 sharedval = 1; 150 151 PTHREAD_REQUIRE(pthread_create(&new, NULL, 152 signal_before_unlock_threadfunc, &sharedval)); 153 154 printf("1: Before waiting.\n"); 155 do { 156 sleep(2); 157 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 158 printf("1: After waiting, in loop.\n"); 159 } while (sharedval != 0); 160 161 printf("1: After the loop.\n"); 162 163 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 164 165 printf("1: After releasing the mutex.\n"); 166 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 167 168 printf("1: Thread joined.\n"); 169 } 170 171 static void * 172 signal_before_unlock_static_init_threadfunc(void *arg) 173 { 174 int *shared = (int *) arg; 175 176 printf("2: Second thread.\n"); 177 178 printf("2: Locking mutex\n"); 179 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 180 printf("2: Got mutex.\n"); 181 printf("Shared value: %d. Changing to 0.\n", *shared); 182 *shared = 0; 183 184 /* Signal first, then unlock, for a different test than #1. */ 185 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 186 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 187 188 return NULL; 189 } 190 191 ATF_TC(signal_before_unlock_static_init); 192 ATF_TC_HEAD(signal_before_unlock_static_init, tc) 193 { 194 atf_tc_set_md_var(tc, "descr", 195 "Checks condition variables: signal before unlocking " 196 "mutex, use static initializers"); 197 } 198 ATF_TC_BODY(signal_before_unlock_static_init, tc) 199 { 200 pthread_t new; 201 void *joinval; 202 int sharedval; 203 204 printf("1: condition variable test 3\n"); 205 206 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 207 208 sharedval = 1; 209 210 PTHREAD_REQUIRE(pthread_create(&new, NULL, 211 signal_before_unlock_static_init_threadfunc, &sharedval)); 212 213 printf("1: Before waiting.\n"); 214 do { 215 sleep(2); 216 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, &static_mutex)); 217 printf("1: After waiting, in loop.\n"); 218 } while (sharedval != 0); 219 220 printf("1: After the loop.\n"); 221 222 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 223 224 printf("1: After releasing the mutex.\n"); 225 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 226 227 printf("1: Thread joined.\n"); 228 } 229 230 static void * 231 signal_wait_race_threadfunc(void *arg) 232 { 233 printf("2: Second thread.\n"); 234 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 235 printf("2: Before the loop.\n"); 236 while (count>0) { 237 count--; 238 total++; 239 toggle = 0; 240 /* printf("2: Before signal %d.\n", count); */ 241 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 242 do { 243 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 244 &static_mutex)); 245 } while (toggle != 1); 246 } 247 printf("2: After the loop.\n"); 248 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 249 250 return NULL; 251 } 252 253 ATF_TC(signal_wait_race); 254 ATF_TC_HEAD(signal_wait_race, tc) 255 { 256 atf_tc_set_md_var(tc, "descr", "Checks condition variables"); 257 } 258 ATF_TC_BODY(signal_wait_race, tc) 259 { 260 pthread_t new; 261 void *joinval; 262 int sharedval; 263 264 printf("1: condition variable test 4\n"); 265 266 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 267 268 count = 50000; 269 toggle = 0; 270 271 PTHREAD_REQUIRE(pthread_create(&new, NULL, signal_wait_race_threadfunc, 272 &sharedval)); 273 274 printf("1: Before waiting.\n"); 275 while (count>0) { 276 count--; 277 total++; 278 toggle = 1; 279 /* printf("1: Before signal %d.\n", count); */ 280 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 281 do { 282 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 283 &static_mutex)); 284 } while (toggle != 0); 285 } 286 printf("1: After the loop.\n"); 287 288 toggle = 1; 289 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 290 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 291 292 printf("1: After releasing the mutex.\n"); 293 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 294 295 printf("1: Thread joined. Final count = %d, total = %d\n", 296 count, total); 297 298 ATF_REQUIRE_EQ(count, 0); 299 ATF_REQUIRE_EQ(total, 50000); 300 } 301 302 static void * 303 pthread_cond_timedwait_func(void *arg) 304 { 305 struct timespec ts; 306 size_t i = 0; 307 int rv; 308 309 for (;;) { 310 311 if (i++ >= 10000) 312 pthread_exit(NULL); 313 314 (void)memset(&ts, 0, sizeof(struct timespec)); 315 316 ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts) == 0); 317 318 /* 319 * Set to one second in the past: 320 * pthread_cond_timedwait(3) should 321 * return ETIMEDOUT immediately. 322 */ 323 ts.tv_sec = ts.tv_sec - 1; 324 325 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 326 rv = pthread_cond_timedwait(&static_cond, &static_mutex, &ts); 327 328 /* 329 * Sometimes we catch ESRCH. 330 * This should never happen. 331 */ 332 ATF_REQUIRE(rv == ETIMEDOUT); 333 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 334 } 335 } 336 337 ATF_TC(cond_timedwait_race); 338 ATF_TC_HEAD(cond_timedwait_race, tc) 339 { 340 atf_tc_set_md_var(tc, "descr", "Test pthread_cond_timedwait(3)"); 341 342 } 343 ATF_TC_BODY(cond_timedwait_race, tc) 344 { 345 pthread_t tid[64]; 346 size_t i, j; 347 348 atf_tc_expect_fail("PR lib/44756"); 349 /* This outer loop is to ensure that a false positive of this race 350 * test does not report the test as broken (due to the test not 351 * triggering the expected failure). However, we want to make this 352 * fail consistently when the race is resolved, and this approach 353 * will have the desired effect. */ 354 for (j = 0; j < 10; j++ ) { 355 for (i = 0; i < __arraycount(tid); i++) { 356 357 PTHREAD_REQUIRE(pthread_create(&tid[i], NULL, 358 pthread_cond_timedwait_func, NULL)); 359 } 360 361 for (i = 0; i < __arraycount(tid); i++) { 362 363 PTHREAD_REQUIRE(pthread_join(tid[i], NULL)); 364 } 365 } 366 } 367 368 static void * 369 broadcast_threadfunc(void *arg) 370 { 371 printf("2: Second thread.\n"); 372 373 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 374 while (count>0) { 375 count--; 376 total++; 377 toggle = 0; 378 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 379 do { 380 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 381 &static_mutex)); 382 } while (toggle != 1); 383 } 384 printf("2: After the loop.\n"); 385 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 386 387 return NULL; 388 } 389 390 391 ATF_TC(broadcast); 392 ATF_TC_HEAD(broadcast, tc) 393 { 394 atf_tc_set_md_var(tc, "descr", 395 "Checks condition variables: use pthread_cond_broadcast()"); 396 } 397 ATF_TC_BODY(broadcast, tc) 398 { 399 pthread_t new; 400 void *joinval; 401 int sharedval; 402 403 printf("1: condition variable test 5\n"); 404 405 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 406 407 count = 50000; 408 toggle = 0; 409 410 PTHREAD_REQUIRE(pthread_create(&new, NULL, broadcast_threadfunc, 411 &sharedval)); 412 413 printf("1: Before waiting.\n"); 414 while (count>0) { 415 count--; 416 total++; 417 toggle = 1; 418 PTHREAD_REQUIRE(pthread_cond_broadcast(&static_cond)); 419 do { 420 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 421 &static_mutex)); 422 } while (toggle != 0); 423 } 424 printf("1: After the loop.\n"); 425 426 toggle = 1; 427 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 428 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 429 430 printf("1: After releasing the mutex.\n"); 431 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 432 433 printf("1: Thread joined. Final count = %d, total = %d\n", count, 434 total); 435 436 ATF_REQUIRE_EQ(count, 0); 437 ATF_REQUIRE_EQ(total, 50000); 438 } 439 440 static void * 441 bogus_timedwaits_threadfunc(void *arg) 442 { 443 return NULL; 444 } 445 446 ATF_TC(bogus_timedwaits); 447 ATF_TC_HEAD(bogus_timedwaits, tc) 448 { 449 atf_tc_set_md_var(tc, "descr", 450 "Checks condition variables: bogus timedwaits"); 451 } 452 ATF_TC_BODY(bogus_timedwaits, tc) 453 { 454 pthread_t new; 455 struct timespec ts; 456 struct timeval tv; 457 458 printf("condition variable test 6: bogus timedwaits\n"); 459 460 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 461 462 printf("unthreaded test (past)\n"); 463 gettimeofday(&tv, NULL); 464 tv.tv_sec -= 2; /* Place the time in the past */ 465 TIMEVAL_TO_TIMESPEC(&tv, &ts); 466 467 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 468 &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) in the " 469 "past"); 470 471 printf("unthreaded test (zero time)\n"); 472 tv.tv_sec = 0; 473 tv.tv_usec = 0; 474 TIMEVAL_TO_TIMESPEC(&tv, &ts); 475 476 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 477 &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) with zero " 478 "time"); 479 480 PTHREAD_REQUIRE(pthread_create(&new, NULL, bogus_timedwaits_threadfunc, 481 NULL)); 482 PTHREAD_REQUIRE(pthread_join(new, NULL)); 483 484 printf("threaded test\n"); 485 gettimeofday(&tv, NULL); 486 tv.tv_sec -= 2; /* Place the time in the past */ 487 TIMEVAL_TO_TIMESPEC(&tv, &ts); 488 489 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 490 &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) in the past"); 491 492 printf("threaded test (zero time)\n"); 493 tv.tv_sec = 0; 494 tv.tv_usec = 0; 495 TIMEVAL_TO_TIMESPEC(&tv, &ts); 496 497 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 498 &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) with zero " 499 "time"); 500 501 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 502 } 503 504 static void 505 unlock(void *arg) 506 { 507 pthread_mutex_unlock((pthread_mutex_t *)arg); 508 } 509 510 static void * 511 destroy_after_cancel_threadfunc(void *arg) 512 { 513 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 514 515 pthread_cleanup_push(unlock, &mutex); 516 517 while (1) { 518 share = 1; 519 PTHREAD_REQUIRE(pthread_cond_broadcast(&cond)); 520 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 521 } 522 523 pthread_cleanup_pop(0); 524 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 525 526 return NULL; 527 } 528 529 ATF_TC(destroy_after_cancel); 530 ATF_TC_HEAD(destroy_after_cancel, tc) 531 { 532 atf_tc_set_md_var(tc, "descr", "Checks destroying a condition variable " 533 "after cancelling a wait"); 534 } 535 ATF_TC_BODY(destroy_after_cancel, tc) 536 { 537 pthread_t thread; 538 539 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); 540 PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL)); 541 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 542 PTHREAD_REQUIRE(pthread_create(&thread, NULL, 543 destroy_after_cancel_threadfunc, NULL)); 544 545 while (share == 0) { 546 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 547 } 548 549 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 550 PTHREAD_REQUIRE(pthread_cancel(thread)); 551 552 PTHREAD_REQUIRE(pthread_join(thread, NULL)); 553 PTHREAD_REQUIRE(pthread_cond_destroy(&cond)); 554 555 PTHREAD_REQUIRE(pthread_mutex_destroy(&mutex)); 556 } 557 558 ATF_TP_ADD_TCS(tp) 559 { 560 561 ATF_TP_ADD_TC(tp, signal_delay_wait); 562 ATF_TP_ADD_TC(tp, signal_before_unlock); 563 ATF_TP_ADD_TC(tp, signal_before_unlock_static_init); 564 ATF_TP_ADD_TC(tp, signal_wait_race); 565 ATF_TP_ADD_TC(tp, cond_timedwait_race); 566 ATF_TP_ADD_TC(tp, broadcast); 567 ATF_TP_ADD_TC(tp, bogus_timedwaits); 568 ATF_TP_ADD_TC(tp, destroy_after_cancel); 569 570 return atf_no_error(); 571 } 572