1 /* $NetBSD: t_cond.c,v 1.1 2010/07/16 15:42:53 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.1 2010/07/16 15:42:53 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 *share = (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", *share); 62 *share = 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 *share = (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", *share); 123 *share = 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 *share = (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", *share); 186 *share = 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 broadcast_threadfunc(void *arg) 310 { 311 printf("2: Second thread.\n"); 312 313 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 314 while (count>0) { 315 count--; 316 total++; 317 toggle = 0; 318 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 319 do { 320 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 321 &static_mutex)); 322 } while (toggle != 1); 323 } 324 printf("2: After the loop.\n"); 325 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 326 327 return NULL; 328 } 329 330 331 ATF_TC(broadcast); 332 ATF_TC_HEAD(broadcast, tc) 333 { 334 atf_tc_set_md_var(tc, "descr", 335 "Checks condition variables: use pthread_cond_broadcast()"); 336 } 337 ATF_TC_BODY(broadcast, tc) 338 { 339 pthread_t new; 340 void *joinval; 341 int sharedval; 342 343 printf("1: condition variable test 5\n"); 344 345 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 346 347 count = 50000; 348 toggle = 0; 349 350 PTHREAD_REQUIRE(pthread_create(&new, NULL, broadcast_threadfunc, 351 &sharedval)); 352 353 printf("1: Before waiting.\n"); 354 while (count>0) { 355 count--; 356 total++; 357 toggle = 1; 358 PTHREAD_REQUIRE(pthread_cond_broadcast(&static_cond)); 359 do { 360 PTHREAD_REQUIRE(pthread_cond_wait(&static_cond, 361 &static_mutex)); 362 } while (toggle != 0); 363 } 364 printf("1: After the loop.\n"); 365 366 toggle = 1; 367 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 368 PTHREAD_REQUIRE(pthread_cond_signal(&static_cond)); 369 370 printf("1: After releasing the mutex.\n"); 371 PTHREAD_REQUIRE(pthread_join(new, &joinval)); 372 373 printf("1: Thread joined. Final count = %d, total = %d\n", count, 374 total); 375 376 ATF_REQUIRE_EQ(count, 0); 377 ATF_REQUIRE_EQ(total, 50000); 378 } 379 380 static void * 381 bogus_timedwaits_threadfunc(void *arg) 382 { 383 return NULL; 384 } 385 386 ATF_TC(bogus_timedwaits); 387 ATF_TC_HEAD(bogus_timedwaits, tc) 388 { 389 atf_tc_set_md_var(tc, "descr", 390 "Checks condition variables: bogus timedwaits"); 391 } 392 ATF_TC_BODY(bogus_timedwaits, tc) 393 { 394 pthread_t new; 395 struct timespec ts; 396 struct timeval tv; 397 398 printf("condition variable test 6: bogus timedwaits\n"); 399 400 PTHREAD_REQUIRE(pthread_mutex_lock(&static_mutex)); 401 402 printf("unthreaded test (past)\n"); 403 gettimeofday(&tv, NULL); 404 tv.tv_sec -= 2; /* Place the time in the past */ 405 TIMEVAL_TO_TIMESPEC(&tv, &ts); 406 407 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 408 &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) in the " 409 "past"); 410 411 printf("unthreaded test (zero time)\n"); 412 tv.tv_sec = 0; 413 tv.tv_usec = 0; 414 TIMEVAL_TO_TIMESPEC(&tv, &ts); 415 416 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 417 &ts), ETIMEDOUT, "pthread_cond_timedwait() (unthreaded) with zero " 418 "time"); 419 420 PTHREAD_REQUIRE(pthread_create(&new, NULL, bogus_timedwaits_threadfunc, 421 NULL)); 422 PTHREAD_REQUIRE(pthread_join(new, NULL)); 423 424 printf("threaded test\n"); 425 gettimeofday(&tv, NULL); 426 tv.tv_sec -= 2; /* Place the time in the past */ 427 TIMEVAL_TO_TIMESPEC(&tv, &ts); 428 429 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 430 &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) in the past"); 431 432 printf("threaded test (zero time)\n"); 433 tv.tv_sec = 0; 434 tv.tv_usec = 0; 435 TIMEVAL_TO_TIMESPEC(&tv, &ts); 436 437 ATF_REQUIRE_EQ_MSG(pthread_cond_timedwait(&static_cond, &static_mutex, 438 &ts), ETIMEDOUT, "pthread_cond_timedwait() (threaded) with zero " 439 "time"); 440 441 PTHREAD_REQUIRE(pthread_mutex_unlock(&static_mutex)); 442 } 443 444 static void 445 unlock(void *arg) 446 { 447 pthread_mutex_unlock((pthread_mutex_t *)arg); 448 } 449 450 static void * 451 destroy_after_cancel_threadfunc(void *arg) 452 { 453 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 454 455 pthread_cleanup_push(unlock, &mutex); 456 457 while (1) { 458 share = 1; 459 PTHREAD_REQUIRE(pthread_cond_broadcast(&cond)); 460 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 461 } 462 463 pthread_cleanup_pop(0); 464 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 465 466 return NULL; 467 } 468 469 ATF_TC(destroy_after_cancel); 470 ATF_TC_HEAD(destroy_after_cancel, tc) 471 { 472 atf_tc_set_md_var(tc, "descr", "Checks destroying a condition variable " 473 "after cancelling a wait"); 474 } 475 ATF_TC_BODY(destroy_after_cancel, tc) 476 { 477 pthread_t thread; 478 479 PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); 480 PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL)); 481 PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); 482 PTHREAD_REQUIRE(pthread_create(&thread, NULL, 483 destroy_after_cancel_threadfunc, NULL)); 484 485 while (share == 0) { 486 PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); 487 } 488 489 PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); 490 PTHREAD_REQUIRE(pthread_cancel(thread)); 491 492 PTHREAD_REQUIRE(pthread_join(thread, NULL)); 493 PTHREAD_REQUIRE(pthread_cond_destroy(&cond)); 494 495 PTHREAD_REQUIRE(pthread_mutex_destroy(&mutex)); 496 } 497 498 ATF_TP_ADD_TCS(tp) 499 { 500 501 ATF_TP_ADD_TC(tp, signal_delay_wait); 502 ATF_TP_ADD_TC(tp, signal_before_unlock); 503 ATF_TP_ADD_TC(tp, signal_before_unlock_static_init); 504 ATF_TP_ADD_TC(tp, signal_wait_race); 505 ATF_TP_ADD_TC(tp, broadcast); 506 ATF_TP_ADD_TC(tp, bogus_timedwaits); 507 ATF_TP_ADD_TC(tp, destroy_after_cancel); 508 509 return atf_no_error(); 510 } 511