cvar2.c (23898B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /*********************************************************************** 7 ** 1996 - Netscape Communications Corporation 8 ** 9 ** Name: cvar2.c 10 ** 11 ** Description: Simple test creates several local and global threads; 12 ** half use a single,shared condvar, and the 13 ** other half have their own condvar. The main thread then loops 14 ** notifying them to wakeup. 15 ** 16 ** Modification History: 17 ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 18 ** The debug mode will print all of the printfs associated with this 19 *test. 20 ** The regress mode will be the default mode. Since the regress tool 21 *limits 22 ** the output to a one line status:PASS or FAIL,all of the printf 23 *statements 24 ** have been handled with an if (debug_mode) statement. 25 ***********************************************************************/ 26 27 #include "nspr.h" 28 #include "plerror.h" 29 #include "plgetopt.h" 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 int _debug_on = 0; 36 #define DPRINTF(arg) \ 37 if (_debug_on) printf arg 38 39 #define DEFAULT_COUNT 100 40 #define DEFAULT_THREADS 5 41 PRInt32 count = DEFAULT_COUNT; 42 43 typedef struct threadinfo { 44 PRThread* thread; 45 PRInt32 id; 46 PRBool internal; 47 PRInt32* tcount; 48 PRLock* lock; 49 PRCondVar* cvar; 50 PRIntervalTime timeout; 51 PRInt32 loops; 52 53 PRLock* exitlock; 54 PRCondVar* exitcvar; 55 PRInt32* exitcount; 56 } threadinfo; 57 58 /* 59 ** Make exitcount, tcount static. for Win16. 60 */ 61 static PRInt32 exitcount = 0; 62 static PRInt32 tcount = 0; 63 64 /* Thread that gets notified; many threads share the same condvar */ 65 void PR_CALLBACK SharedCondVarThread(void* _info) { 66 threadinfo* info = (threadinfo*)_info; 67 PRInt32 index; 68 69 for (index = 0; index < info->loops; index++) { 70 PR_Lock(info->lock); 71 if (*info->tcount == 0) { 72 PR_WaitCondVar(info->cvar, info->timeout); 73 } 74 #if 0 75 printf("shared thread %ld notified in loop %ld\n", info->id, index); 76 #endif 77 (*info->tcount)--; 78 PR_Unlock(info->lock); 79 80 PR_Lock(info->exitlock); 81 (*info->exitcount)++; 82 PR_NotifyCondVar(info->exitcvar); 83 PR_Unlock(info->exitlock); 84 } 85 #if 0 86 printf("shared thread %ld terminating\n", info->id); 87 #endif 88 } 89 90 /* Thread that gets notified; no other threads use the same condvar */ 91 void PR_CALLBACK PrivateCondVarThread(void* _info) { 92 threadinfo* info = (threadinfo*)_info; 93 PRInt32 index; 94 95 for (index = 0; index < info->loops; index++) { 96 PR_Lock(info->lock); 97 if (*info->tcount == 0) { 98 DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n", 99 PR_GetCurrentThread(), info->cvar)); 100 PR_WaitCondVar(info->cvar, info->timeout); 101 } 102 #if 0 103 printf("solo thread %ld notified in loop %ld\n", info->id, index); 104 #endif 105 (*info->tcount)--; 106 PR_Unlock(info->lock); 107 108 PR_Lock(info->exitlock); 109 (*info->exitcount)++; 110 PR_NotifyCondVar(info->exitcvar); 111 DPRINTF( 112 ("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = " 113 "%ld\n", 114 PR_GetCurrentThread(), info->exitcvar, (*info->exitcount))); 115 PR_Unlock(info->exitlock); 116 } 117 #if 0 118 printf("solo thread %ld terminating\n", info->id); 119 #endif 120 } 121 122 void CreateTestThread(threadinfo* info, PRInt32 id, PRLock* lock, 123 PRCondVar* cvar, PRInt32 loops, PRIntervalTime timeout, 124 PRInt32* tcount, PRLock* exitlock, PRCondVar* exitcvar, 125 PRInt32* exitcount, PRBool shared, PRThreadScope scope) { 126 info->id = id; 127 info->internal = (shared) ? PR_FALSE : PR_TRUE; 128 info->lock = lock; 129 info->cvar = cvar; 130 info->loops = loops; 131 info->timeout = timeout; 132 info->tcount = tcount; 133 info->exitlock = exitlock; 134 info->exitcvar = exitcvar; 135 info->exitcount = exitcount; 136 info->thread = PR_CreateThread( 137 PR_USER_THREAD, shared ? SharedCondVarThread : PrivateCondVarThread, info, 138 PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); 139 if (!info->thread) { 140 PL_PrintError("error creating thread\n"); 141 } 142 } 143 144 void CondVarTestSUU(void* _arg) { 145 PRInt32 arg = (PRInt32)_arg; 146 PRInt32 index, loops; 147 threadinfo* list; 148 PRLock* sharedlock; 149 PRCondVar* sharedcvar; 150 PRLock* exitlock; 151 PRCondVar* exitcvar; 152 153 exitcount = 0; 154 tcount = 0; 155 list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); 156 157 sharedlock = PR_NewLock(); 158 sharedcvar = PR_NewCondVar(sharedlock); 159 exitlock = PR_NewLock(); 160 exitcvar = PR_NewCondVar(exitlock); 161 162 /* Create the threads */ 163 for (index = 0; index < arg;) { 164 CreateTestThread(&list[index], index, sharedlock, sharedcvar, count, 165 PR_INTERVAL_NO_TIMEOUT, &tcount, exitlock, exitcvar, 166 &exitcount, PR_TRUE, PR_LOCAL_THREAD); 167 index++; 168 DPRINTF(("CondVarTestSUU: created thread 0x%lx\n", list[index].thread)); 169 } 170 171 for (loops = 0; loops < count; loops++) { 172 /* Notify the threads */ 173 for (index = 0; index < (arg); index++) { 174 PR_Lock(list[index].lock); 175 (*list[index].tcount)++; 176 PR_NotifyCondVar(list[index].cvar); 177 PR_Unlock(list[index].lock); 178 DPRINTF(("PrivateCondVarThread: thread 0x%lx notified cvar = 0x%lx\n", 179 PR_GetCurrentThread(), list[index].cvar)); 180 } 181 182 /* Wait for threads to finish */ 183 PR_Lock(exitlock); 184 while (exitcount < arg) { 185 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); 186 } 187 PR_ASSERT(exitcount >= arg); 188 exitcount -= arg; 189 PR_Unlock(exitlock); 190 } 191 192 /* Join all the threads */ 193 for (index = 0; index < (arg); index++) { 194 PR_JoinThread(list[index].thread); 195 } 196 197 PR_DestroyCondVar(sharedcvar); 198 PR_DestroyLock(sharedlock); 199 PR_DestroyCondVar(exitcvar); 200 PR_DestroyLock(exitlock); 201 202 PR_DELETE(list); 203 } 204 205 void CondVarTestSUK(void* _arg) { 206 PRInt32 arg = (PRInt32)_arg; 207 PRInt32 index, loops; 208 threadinfo* list; 209 PRLock* sharedlock; 210 PRCondVar* sharedcvar; 211 PRLock* exitlock; 212 PRCondVar* exitcvar; 213 exitcount = 0; 214 tcount = 0; 215 216 list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); 217 218 sharedlock = PR_NewLock(); 219 sharedcvar = PR_NewCondVar(sharedlock); 220 exitlock = PR_NewLock(); 221 exitcvar = PR_NewCondVar(exitlock); 222 223 /* Create the threads */ 224 for (index = 0; index < arg;) { 225 CreateTestThread(&list[index], index, sharedlock, sharedcvar, count, 226 PR_INTERVAL_NO_TIMEOUT, &tcount, exitlock, exitcvar, 227 &exitcount, PR_TRUE, PR_GLOBAL_THREAD); 228 index++; 229 } 230 231 for (loops = 0; loops < count; loops++) { 232 /* Notify the threads */ 233 for (index = 0; index < (arg); index++) { 234 PR_Lock(list[index].lock); 235 (*list[index].tcount)++; 236 PR_NotifyCondVar(list[index].cvar); 237 PR_Unlock(list[index].lock); 238 } 239 240 #if 0 241 printf("wait for threads to be done\n"); 242 #endif 243 /* Wait for threads to finish */ 244 PR_Lock(exitlock); 245 while (exitcount < arg) { 246 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); 247 } 248 PR_ASSERT(exitcount >= arg); 249 exitcount -= arg; 250 PR_Unlock(exitlock); 251 #if 0 252 printf("threads ready\n"); 253 #endif 254 } 255 256 /* Join all the threads */ 257 for (index = 0; index < (arg); index++) { 258 PR_JoinThread(list[index].thread); 259 } 260 261 PR_DestroyCondVar(sharedcvar); 262 PR_DestroyLock(sharedlock); 263 PR_DestroyCondVar(exitcvar); 264 PR_DestroyLock(exitlock); 265 266 PR_DELETE(list); 267 } 268 269 void CondVarTestPUU(void* _arg) { 270 PRInt32 arg = (PRInt32)_arg; 271 PRInt32 index, loops; 272 threadinfo* list; 273 PRLock* sharedlock; 274 PRCondVar* sharedcvar; 275 PRLock* exitlock; 276 PRCondVar* exitcvar; 277 PRInt32 *tcount, *saved_tcount; 278 279 exitcount = 0; 280 list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); 281 saved_tcount = tcount = (PRInt32*)PR_CALLOC(sizeof(*tcount) * (arg * 4)); 282 283 sharedlock = PR_NewLock(); 284 sharedcvar = PR_NewCondVar(sharedlock); 285 exitlock = PR_NewLock(); 286 exitcvar = PR_NewCondVar(exitlock); 287 288 /* Create the threads */ 289 for (index = 0; index < arg;) { 290 list[index].lock = PR_NewLock(); 291 list[index].cvar = PR_NewCondVar(list[index].lock); 292 CreateTestThread(&list[index], index, list[index].lock, list[index].cvar, 293 count, PR_INTERVAL_NO_TIMEOUT, tcount, exitlock, exitcvar, 294 &exitcount, PR_FALSE, PR_LOCAL_THREAD); 295 296 DPRINTF(("CondVarTestPUU: created thread 0x%lx\n", list[index].thread)); 297 index++; 298 tcount++; 299 } 300 301 for (loops = 0; loops < count; loops++) { 302 /* Notify the threads */ 303 for (index = 0; index < (arg); index++) { 304 PR_Lock(list[index].lock); 305 (*list[index].tcount)++; 306 PR_NotifyCondVar(list[index].cvar); 307 PR_Unlock(list[index].lock); 308 } 309 310 PR_Lock(exitlock); 311 /* Wait for threads to finish */ 312 while (exitcount < arg) { 313 DPRINTF( 314 ("CondVarTestPUU: thread 0x%lx waiting on exitcvar = 0x%lx cnt = " 315 "%ld\n", 316 PR_GetCurrentThread(), exitcvar, exitcount)); 317 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); 318 } 319 PR_ASSERT(exitcount >= arg); 320 exitcount -= arg; 321 PR_Unlock(exitlock); 322 } 323 324 /* Join all the threads */ 325 for (index = 0; index < (arg); index++) { 326 DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n", list[index].thread)); 327 PR_JoinThread(list[index].thread); 328 if (list[index].internal) { 329 PR_Lock(list[index].lock); 330 PR_DestroyCondVar(list[index].cvar); 331 PR_Unlock(list[index].lock); 332 PR_DestroyLock(list[index].lock); 333 } 334 } 335 336 PR_DestroyCondVar(sharedcvar); 337 PR_DestroyLock(sharedlock); 338 PR_DestroyCondVar(exitcvar); 339 PR_DestroyLock(exitlock); 340 341 PR_DELETE(list); 342 PR_DELETE(saved_tcount); 343 } 344 345 void CondVarTestPUK(void* _arg) { 346 PRInt32 arg = (PRInt32)_arg; 347 PRInt32 index, loops; 348 threadinfo* list; 349 PRLock* sharedlock; 350 PRCondVar* sharedcvar; 351 PRLock* exitlock; 352 PRCondVar* exitcvar; 353 PRInt32 *tcount, *saved_tcount; 354 355 exitcount = 0; 356 list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); 357 saved_tcount = tcount = (PRInt32*)PR_CALLOC(sizeof(*tcount) * (arg * 4)); 358 359 sharedlock = PR_NewLock(); 360 sharedcvar = PR_NewCondVar(sharedlock); 361 exitlock = PR_NewLock(); 362 exitcvar = PR_NewCondVar(exitlock); 363 364 /* Create the threads */ 365 for (index = 0; index < arg;) { 366 list[index].lock = PR_NewLock(); 367 list[index].cvar = PR_NewCondVar(list[index].lock); 368 CreateTestThread(&list[index], index, list[index].lock, list[index].cvar, 369 count, PR_INTERVAL_NO_TIMEOUT, tcount, exitlock, exitcvar, 370 &exitcount, PR_FALSE, PR_GLOBAL_THREAD); 371 372 index++; 373 tcount++; 374 } 375 376 for (loops = 0; loops < count; loops++) { 377 /* Notify the threads */ 378 for (index = 0; index < (arg); index++) { 379 PR_Lock(list[index].lock); 380 (*list[index].tcount)++; 381 PR_NotifyCondVar(list[index].cvar); 382 PR_Unlock(list[index].lock); 383 } 384 385 /* Wait for threads to finish */ 386 PR_Lock(exitlock); 387 while (exitcount < arg) { 388 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); 389 } 390 PR_ASSERT(exitcount >= arg); 391 exitcount -= arg; 392 PR_Unlock(exitlock); 393 } 394 395 /* Join all the threads */ 396 for (index = 0; index < (arg); index++) { 397 PR_JoinThread(list[index].thread); 398 if (list[index].internal) { 399 PR_Lock(list[index].lock); 400 PR_DestroyCondVar(list[index].cvar); 401 PR_Unlock(list[index].lock); 402 PR_DestroyLock(list[index].lock); 403 } 404 } 405 406 PR_DestroyCondVar(sharedcvar); 407 PR_DestroyLock(sharedlock); 408 PR_DestroyCondVar(exitcvar); 409 PR_DestroyLock(exitlock); 410 411 PR_DELETE(list); 412 PR_DELETE(saved_tcount); 413 } 414 415 void CondVarTest(void* _arg) { 416 PRInt32 arg = (PRInt32)_arg; 417 PRInt32 index, loops; 418 threadinfo* list; 419 PRLock* sharedlock; 420 PRCondVar* sharedcvar; 421 PRLock* exitlock; 422 PRCondVar* exitcvar; 423 PRInt32 *ptcount, *saved_ptcount; 424 425 exitcount = 0; 426 tcount = 0; 427 list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); 428 saved_ptcount = ptcount = (PRInt32*)PR_CALLOC(sizeof(*ptcount) * (arg * 4)); 429 430 sharedlock = PR_NewLock(); 431 sharedcvar = PR_NewCondVar(sharedlock); 432 exitlock = PR_NewLock(); 433 exitcvar = PR_NewCondVar(exitlock); 434 435 /* Create the threads */ 436 for (index = 0; index < arg * 4;) { 437 CreateTestThread(&list[index], index, sharedlock, sharedcvar, count, 438 PR_INTERVAL_NO_TIMEOUT, &tcount, exitlock, exitcvar, 439 &exitcount, PR_TRUE, PR_LOCAL_THREAD); 440 441 index++; 442 CreateTestThread(&list[index], index, sharedlock, sharedcvar, count, 443 PR_INTERVAL_NO_TIMEOUT, &tcount, exitlock, exitcvar, 444 &exitcount, PR_TRUE, PR_GLOBAL_THREAD); 445 446 index++; 447 list[index].lock = PR_NewLock(); 448 list[index].cvar = PR_NewCondVar(list[index].lock); 449 CreateTestThread(&list[index], index, list[index].lock, list[index].cvar, 450 count, PR_INTERVAL_NO_TIMEOUT, ptcount, exitlock, exitcvar, 451 &exitcount, PR_FALSE, PR_LOCAL_THREAD); 452 index++; 453 ptcount++; 454 list[index].lock = PR_NewLock(); 455 list[index].cvar = PR_NewCondVar(list[index].lock); 456 CreateTestThread(&list[index], index, list[index].lock, list[index].cvar, 457 count, PR_INTERVAL_NO_TIMEOUT, ptcount, exitlock, exitcvar, 458 &exitcount, PR_FALSE, PR_GLOBAL_THREAD); 459 460 index++; 461 ptcount++; 462 } 463 464 for (loops = 0; loops < count; loops++) { 465 /* Notify the threads */ 466 for (index = 0; index < (arg * 4); index++) { 467 PR_Lock(list[index].lock); 468 (*list[index].tcount)++; 469 PR_NotifyCondVar(list[index].cvar); 470 PR_Unlock(list[index].lock); 471 } 472 473 #if 0 474 printf("wait for threads done\n"); 475 #endif 476 477 /* Wait for threads to finish */ 478 PR_Lock(exitlock); 479 while (exitcount < arg * 4) { 480 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); 481 } 482 PR_ASSERT(exitcount >= arg * 4); 483 exitcount -= arg * 4; 484 PR_Unlock(exitlock); 485 #if 0 486 printf("threads ready\n"); 487 #endif 488 } 489 490 /* Join all the threads */ 491 for (index = 0; index < (arg * 4); index++) { 492 PR_JoinThread(list[index].thread); 493 if (list[index].internal) { 494 PR_Lock(list[index].lock); 495 PR_DestroyCondVar(list[index].cvar); 496 PR_Unlock(list[index].lock); 497 PR_DestroyLock(list[index].lock); 498 } 499 } 500 501 PR_DestroyCondVar(sharedcvar); 502 PR_DestroyLock(sharedlock); 503 PR_DestroyCondVar(exitcvar); 504 PR_DestroyLock(exitlock); 505 506 PR_DELETE(list); 507 PR_DELETE(saved_ptcount); 508 } 509 510 void CondVarTimeoutTest(void* _arg) { 511 PRInt32 arg = (PRInt32)_arg; 512 PRInt32 index, loops; 513 threadinfo* list; 514 PRLock* sharedlock; 515 PRCondVar* sharedcvar; 516 PRLock* exitlock; 517 PRCondVar* exitcvar; 518 519 list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); 520 521 sharedlock = PR_NewLock(); 522 sharedcvar = PR_NewCondVar(sharedlock); 523 exitlock = PR_NewLock(); 524 exitcvar = PR_NewCondVar(exitlock); 525 526 /* Create the threads */ 527 for (index = 0; index < arg * 4;) { 528 CreateTestThread(&list[index], index, sharedlock, sharedcvar, count, 529 PR_MillisecondsToInterval(50), &tcount, exitlock, exitcvar, 530 &exitcount, PR_TRUE, PR_LOCAL_THREAD); 531 index++; 532 CreateTestThread(&list[index], index, sharedlock, sharedcvar, count, 533 PR_MillisecondsToInterval(50), &tcount, exitlock, exitcvar, 534 &exitcount, PR_TRUE, PR_GLOBAL_THREAD); 535 index++; 536 list[index].lock = PR_NewLock(); 537 list[index].cvar = PR_NewCondVar(list[index].lock); 538 CreateTestThread(&list[index], index, list[index].lock, list[index].cvar, 539 count, PR_MillisecondsToInterval(50), &tcount, exitlock, 540 exitcvar, &exitcount, PR_FALSE, PR_LOCAL_THREAD); 541 index++; 542 543 list[index].lock = PR_NewLock(); 544 list[index].cvar = PR_NewCondVar(list[index].lock); 545 CreateTestThread(&list[index], index, list[index].lock, list[index].cvar, 546 count, PR_MillisecondsToInterval(50), &tcount, exitlock, 547 exitcvar, &exitcount, PR_FALSE, PR_GLOBAL_THREAD); 548 549 index++; 550 } 551 552 for (loops = 0; loops < count; loops++) { 553 /* Wait for threads to finish */ 554 PR_Lock(exitlock); 555 while (exitcount < arg * 4) { 556 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); 557 } 558 PR_ASSERT(exitcount >= arg * 4); 559 exitcount -= arg * 4; 560 PR_Unlock(exitlock); 561 } 562 563 /* Join all the threads */ 564 for (index = 0; index < (arg * 4); index++) { 565 PR_JoinThread(list[index].thread); 566 if (list[index].internal) { 567 PR_Lock(list[index].lock); 568 PR_DestroyCondVar(list[index].cvar); 569 PR_Unlock(list[index].lock); 570 PR_DestroyLock(list[index].lock); 571 } 572 } 573 574 PR_DestroyCondVar(sharedcvar); 575 PR_DestroyLock(sharedlock); 576 PR_DestroyCondVar(exitcvar); 577 PR_DestroyLock(exitlock); 578 579 PR_DELETE(list); 580 } 581 582 void CondVarMixedTest(void* _arg) { 583 PRInt32 arg = (PRInt32)_arg; 584 PRInt32 index, loops; 585 threadinfo* list; 586 PRLock* sharedlock; 587 PRCondVar* sharedcvar; 588 PRLock* exitlock; 589 PRCondVar* exitcvar; 590 PRInt32* ptcount; 591 592 exitcount = 0; 593 tcount = 0; 594 list = (threadinfo*)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); 595 ptcount = (PRInt32*)PR_CALLOC(sizeof(*ptcount) * (arg * 4)); 596 597 sharedlock = PR_NewLock(); 598 sharedcvar = PR_NewCondVar(sharedlock); 599 exitlock = PR_NewLock(); 600 exitcvar = PR_NewCondVar(exitlock); 601 602 /* Create the threads */ 603 for (index = 0; index < arg * 4;) { 604 CreateTestThread(&list[index], index, sharedlock, sharedcvar, count, 605 PR_MillisecondsToInterval(50), &tcount, exitlock, exitcvar, 606 &exitcount, PR_TRUE, PR_LOCAL_THREAD); 607 index++; 608 CreateTestThread(&list[index], index, sharedlock, sharedcvar, count, 609 PR_MillisecondsToInterval(50), &tcount, exitlock, exitcvar, 610 &exitcount, PR_TRUE, PR_GLOBAL_THREAD); 611 index++; 612 list[index].lock = PR_NewLock(); 613 list[index].cvar = PR_NewCondVar(list[index].lock); 614 CreateTestThread(&list[index], index, list[index].lock, list[index].cvar, 615 count, PR_MillisecondsToInterval(50), ptcount, exitlock, 616 exitcvar, &exitcount, PR_FALSE, PR_LOCAL_THREAD); 617 index++; 618 ptcount++; 619 620 list[index].lock = PR_NewLock(); 621 list[index].cvar = PR_NewCondVar(list[index].lock); 622 CreateTestThread(&list[index], index, list[index].lock, list[index].cvar, 623 count, PR_MillisecondsToInterval(50), ptcount, exitlock, 624 exitcvar, &exitcount, PR_FALSE, PR_GLOBAL_THREAD); 625 index++; 626 ptcount++; 627 } 628 629 /* Notify every 3rd thread */ 630 for (loops = 0; loops < count; loops++) { 631 /* Notify the threads */ 632 for (index = 0; index < (arg * 4); index += 3) { 633 PR_Lock(list[index].lock); 634 *list[index].tcount++; 635 PR_NotifyCondVar(list[index].cvar); 636 PR_Unlock(list[index].lock); 637 } 638 /* Wait for threads to finish */ 639 PR_Lock(exitlock); 640 while (exitcount < arg * 4) { 641 PR_WaitCondVar(exitcvar, PR_SecondsToInterval(60)); 642 } 643 PR_ASSERT(exitcount >= arg * 4); 644 exitcount -= arg * 4; 645 PR_Unlock(exitlock); 646 } 647 648 /* Join all the threads */ 649 for (index = 0; index < (arg * 4); index++) { 650 PR_JoinThread(list[index].thread); 651 if (list[index].internal) { 652 PR_Lock(list[index].lock); 653 PR_DestroyCondVar(list[index].cvar); 654 PR_Unlock(list[index].lock); 655 PR_DestroyLock(list[index].lock); 656 } 657 } 658 659 PR_DestroyCondVar(sharedcvar); 660 PR_DestroyLock(sharedlock); 661 662 PR_DELETE(list); 663 } 664 665 void CondVarCombinedTest(void* arg) { 666 PRThread* threads[3]; 667 668 threads[0] = PR_CreateThread(PR_USER_THREAD, CondVarTest, (void*)arg, 669 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, 670 PR_JOINABLE_THREAD, 0); 671 threads[1] = PR_CreateThread(PR_USER_THREAD, CondVarTimeoutTest, (void*)arg, 672 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, 673 PR_JOINABLE_THREAD, 0); 674 threads[2] = PR_CreateThread(PR_USER_THREAD, CondVarMixedTest, (void*)arg, 675 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, 676 PR_JOINABLE_THREAD, 0); 677 678 PR_JoinThread(threads[0]); 679 PR_JoinThread(threads[1]); 680 PR_JoinThread(threads[2]); 681 } 682 683 /************************************************************************/ 684 685 static void Measure(void (*func)(void*), PRInt32 arg, const char* msg) { 686 PRIntervalTime start, stop; 687 double d; 688 689 start = PR_IntervalNow(); 690 (*func)((void*)arg); 691 stop = PR_IntervalNow(); 692 693 d = (double)PR_IntervalToMicroseconds(stop - start); 694 695 printf("%40s: %6.2f usec\n", msg, d / count); 696 } 697 698 static PRIntn PR_CALLBACK RealMain(int argc, char** argv) { 699 PRInt32 threads, default_threads = DEFAULT_THREADS; 700 PLOptStatus os; 701 PLOptState* opt = PL_CreateOptState(argc, argv, "vc:t:"); 702 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 703 if (PL_OPT_BAD == os) { 704 continue; 705 } 706 switch (opt->option) { 707 case 'v': /* debug mode */ 708 _debug_on = 1; 709 break; 710 case 'c': /* loop counter */ 711 count = atoi(opt->value); 712 break; 713 case 't': /* number of threads involved */ 714 default_threads = atoi(opt->value); 715 break; 716 default: 717 break; 718 } 719 } 720 PL_DestroyOptState(opt); 721 722 if (0 == count) { 723 count = DEFAULT_COUNT; 724 } 725 if (0 == default_threads) { 726 default_threads = DEFAULT_THREADS; 727 } 728 729 printf( 730 "\n\ 731 CondVar Test: \n\ 732 \n\ 733 Simple test creates several local and global threads; half use a single,\n\ 734 shared condvar, and the other half have their own condvar. The main \n\ 735 thread then loops notifying them to wakeup. \n\ 736 \n\ 737 The timeout test is very similar except that the threads are not \n\ 738 notified. They will all wakeup on a 1 second timeout. \n\ 739 \n\ 740 The mixed test combines the simple test and the timeout test; every \n\ 741 third thread is notified, the other threads are expected to timeout \n\ 742 correctly. \n\ 743 \n\ 744 Lastly, the combined test creates a thread for each of the above three \n\ 745 cases and they all run simultaneously. \n\ 746 \n\ 747 This test is run with %d, %d, %d, and %d threads of each type.\n\n", 748 default_threads, default_threads * 2, default_threads * 3, 749 default_threads * 4); 750 751 PR_SetConcurrency(2); 752 753 for (threads = default_threads; threads < default_threads * 5; 754 threads += default_threads) { 755 printf("\n%ld Thread tests\n", threads); 756 Measure(CondVarTestSUU, threads, "Condvar simple test shared UU"); 757 Measure(CondVarTestSUK, threads, "Condvar simple test shared UK"); 758 Measure(CondVarTestPUU, threads, "Condvar simple test priv UU"); 759 Measure(CondVarTestPUK, threads, "Condvar simple test priv UK"); 760 Measure(CondVarTest, threads, "Condvar simple test All"); 761 Measure(CondVarTimeoutTest, threads, "Condvar timeout test"); 762 #if 0 763 Measure(CondVarMixedTest, threads, "Condvar mixed timeout test"); 764 Measure(CondVarCombinedTest, threads, "Combined condvar test"); 765 #endif 766 } 767 768 printf("PASS\n"); 769 770 return 0; 771 } 772 773 int main(int argc, char** argv) { 774 PRIntn rv; 775 776 rv = PR_Initialize(RealMain, argc, argv, 0); 777 return rv; 778 } /* main */