1 /* $NetBSD: t_cond.c,v 1.3 2011/03/27 16:45:15 jruoho 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.3 2011/03/27 16:45:15 jruoho 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; 353 354 atf_tc_expect_fail("PR lib/44756"); 355 356 for (i = 0; i < __arraycount(tid); i++) { 357 358 PTHREAD_REQUIRE(pthread_create(&tid[i], NULL, 359 pthread_cond_timedwait_func, NULL)); 360 } 361 362 for (i = 0; i < __arraycount(tid); i++) { 363 364 PTHREAD_REQUIRE(pthread_join(tid[i], NULL)); 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