1 /* $NetBSD: t_cond.c,v 1.6 2014/09/03 16:23:24 gson 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.6 2014/09/03 16:23:24 gson 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; 347 348 for (i = 0; i < __arraycount(tid); i++) { 349 350 PTHREAD_REQUIRE(pthread_create(&tid[i], NULL, 351 pthread_cond_timedwait_func, NULL)); 352 } 353 354 for (i = 0; i < __arraycount(tid); i++) { 355 356 PTHREAD_REQUIRE(pthread_join(tid[i], NULL)); 357 } 358 } 359 360 static void * 361 broadcast_threadfunc(void *arg) 362 { 363 printf("2: Second thread.\n"); 364 365 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 366 while (count>0) { 367 count--; 368 total++; 369 toggle = 0; 370 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 371 do { 372 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 373 &static_mutex)); 374 } while (toggle != 1); 375 } 376 printf("2: After the loop.\n"); 377 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 378 379 return NULL; 380 } 381 382 383 ATF_TC(broadcast); 384 ATF_TC_HEAD(broadcast, tc) 385 { 386 atf_tc_set_md_var(tc, "descr", 387 "Checks condition variables: use pthread_cond_broadcast()"); 388 } 389 ATF_TC_BODY(broadcast, tc) 390 { 391 pthread_t new; 392 void *joinval; 393 int sharedval; 394 395 printf("1: condition variable test 5\n"); 396 397 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 398 399 count = 50000; 400 toggle = 0; 401 402 PTHREAD_REQUIRE(pthread_create(&new, NULL, broadcast_threadfunc, 403 &sharedval)); 404 405 printf("1: Before waiting.\n"); 406 while (count>0) { 407 count--; 408 total++; 409 toggle = 1; 410 PTHREAD_REQUIRE(pthread_cond_broadcast(&static_cond)); 411 do { 412 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 413 &static_mutex)); 414 } while (toggle != 0); 415 } 416 printf("1: After the loop.\n"); 417 418 toggle = 1; 419 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 420 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 421 422 printf("1: After releasing the mutex.\n"); 423 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 424 425 printf("1: Thread joined. Final count = %d, total = %d\n", count, 426 total); 427 428 ATF_REQUIRE_EQ(count, 0); 429 ATF_REQUIRE_EQ(total, 50000); 430 } 431 432 static void * 433 bogus_timedwaits_threadfunc(void *arg) 434 { 435 return NULL; 436 } 437 438 ATF_TC(bogus_timedwaits); 439 ATF_TC_HEAD(bogus_timedwaits, tc) 440 { 441 atf_tc_set_md_var(tc, "descr", 442 "Checks condition variables: bogus timedwaits"); 443 } 444 ATF_TC_BODY(bogus_timedwaits, tc) 445 { 446 pthread_t new; 447 struct timespec ts; 448 struct timeval tv; 449 450 printf("condition variable test 6: bogus timedwaits\n"); 451 452 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 453 454 printf("unthreaded test (past)\n"); 455 gettimeofday(&tv, NULL); 456 tv.tv_sec -= 2; /* Place the time in the past */ 457 TIMEVAL_TO_TIMESPEC(&tv, &ts); 458 459 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 460 &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) in the " 461 "past"); 462 463 printf("unthreaded test (zero time)\n"); 464 tv.tv_sec = 0; 465 tv.tv_usec = 0; 466 TIMEVAL_TO_TIMESPEC(&tv, &ts); 467 468 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 469 &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) with zero " 470 "time"); 471 472 PTHREAD_REQUIRE(pthread_create(&new, NULL, bogus_timedwaits_threadfunc, 473 NULL)); 474 PTHREAD_REQUIRE(pthread_join(new, NULL)); 475 476 printf("threaded test\n"); 477 gettimeofday(&tv, NULL); 478 tv.tv_sec -= 2; /* Place the time in the past */ 479 TIMEVAL_TO_TIMESPEC(&tv, &ts); 480 481 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 482 &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) in the past"); 483 484 printf("threaded test (zero time)\n"); 485 tv.tv_sec = 0; 486 tv.tv_usec = 0; 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) with zero " 491 "time"); 492 493 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 494 } 495 496 static void 497 unlock(void *arg) 498 { 499 pthread_mutex_unlock((pthread_mutex_t *)arg); 500 } 501 502 static void * 503 destroy_after_cancel_threadfunc(void *arg) 504 { 505 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 506 507 pthread_cleanup_push(unlock, &mutex); 508 509 while (1) { 510 share = 1; 511 PTHREAD_REQUIRE(pthread_cond_broadcast(&cond)); 512 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 513 } 514 515 pthread_cleanup_pop(0); 516 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 517 518 return NULL; 519 } 520 521 ATF_TC(destroy_after_cancel); 522 ATF_TC_HEAD(destroy_after_cancel, tc) 523 { 524 atf_tc_set_md_var(tc, "descr", "Checks destroying a condition variable " 525 "after cancelling a wait"); 526 } 527 ATF_TC_BODY(destroy_after_cancel, tc) 528 { 529 pthread_t thread; 530 531 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); 532 PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL)); 533 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 534 PTHREAD_REQUIRE(pthread_create(&thread, NULL, 535 destroy_after_cancel_threadfunc, NULL)); 536 537 while (share == 0) { 538 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 539 } 540 541 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 542 PTHREAD_REQUIRE(pthread_cancel(thread)); 543 544 PTHREAD_REQUIRE(pthread_join(thread, NULL)); 545 PTHREAD_REQUIRE(pthread_cond_destroy(&cond)); 546 547 PTHREAD_REQUIRE(pthread_mutex_destroy(&mutex)); 548 } 549 550 ATF_TP_ADD_TCS(tp) 551 { 552 553 ATF_TP_ADD_TC(tp, signal_delay_wait); 554 ATF_TP_ADD_TC(tp, signal_before_unlock); 555 ATF_TP_ADD_TC(tp, signal_before_unlock_static_init); 556 ATF_TP_ADD_TC(tp, signal_wait_race); 557 ATF_TP_ADD_TC(tp, cond_timedwait_race); 558 ATF_TP_ADD_TC(tp, broadcast); 559 ATF_TP_ADD_TC(tp, bogus_timedwaits); 560 ATF_TP_ADD_TC(tp, destroy_after_cancel); 561 562 return atf_no_error(); 563 } 564