prucv.c (17734B)
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 #include "primpl.h" 7 #include "prinrval.h" 8 #include "prtypes.h" 9 10 #if defined(WIN95) 11 /* 12 ** Some local variables report warnings on Win95 because the code paths 13 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS. 14 ** The pragma suppresses the warning. 15 ** 16 */ 17 # pragma warning(disable : 4101) 18 #endif 19 20 /* 21 ** Notify one thread that it has finished waiting on a condition variable 22 ** Caller must hold the _PR_CVAR_LOCK(cv) 23 */ 24 PRBool _PR_NotifyThread(PRThread* thread, PRThread* me) { 25 PRBool rv; 26 27 PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); 28 29 _PR_THREAD_LOCK(thread); 30 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 31 if (!_PR_IS_NATIVE_THREAD(thread)) { 32 if (thread->wait.cvar != NULL) { 33 thread->wait.cvar = NULL; 34 35 _PR_SLEEPQ_LOCK(thread->cpu); 36 /* The notify and timeout can collide; in which case both may 37 * attempt to delete from the sleepQ; only let one do it. 38 */ 39 if (thread->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)) { 40 _PR_DEL_SLEEPQ(thread, PR_TRUE); 41 } 42 _PR_SLEEPQ_UNLOCK(thread->cpu); 43 44 if (thread->flags & _PR_SUSPENDING) { 45 /* 46 * set thread state to SUSPENDED; a Resume operation 47 * on the thread will move it to the runQ 48 */ 49 thread->state = _PR_SUSPENDED; 50 _PR_MISCQ_LOCK(thread->cpu); 51 _PR_ADD_SUSPENDQ(thread, thread->cpu); 52 _PR_MISCQ_UNLOCK(thread->cpu); 53 _PR_THREAD_UNLOCK(thread); 54 } else { 55 /* Make thread runnable */ 56 thread->state = _PR_RUNNABLE; 57 _PR_THREAD_UNLOCK(thread); 58 59 _PR_AddThreadToRunQ(me, thread); 60 _PR_MD_WAKEUP_WAITER(thread); 61 } 62 63 rv = PR_TRUE; 64 } else { 65 /* Thread has already been notified */ 66 _PR_THREAD_UNLOCK(thread); 67 rv = PR_FALSE; 68 } 69 } else { /* If the thread is a native thread */ 70 if (thread->wait.cvar) { 71 thread->wait.cvar = NULL; 72 73 if (thread->flags & _PR_SUSPENDING) { 74 /* 75 * set thread state to SUSPENDED; a Resume operation 76 * on the thread will enable the thread to run 77 */ 78 thread->state = _PR_SUSPENDED; 79 } else { 80 thread->state = _PR_RUNNING; 81 } 82 _PR_THREAD_UNLOCK(thread); 83 _PR_MD_WAKEUP_WAITER(thread); 84 rv = PR_TRUE; 85 } else { 86 _PR_THREAD_UNLOCK(thread); 87 rv = PR_FALSE; 88 } 89 } 90 91 return rv; 92 } 93 94 /* 95 * Notify thread waiting on cvar; called when thread is interrupted 96 * The thread lock is held on entry and released before return 97 */ 98 void _PR_NotifyLockedThread(PRThread* thread) { 99 PRThread* me = _PR_MD_CURRENT_THREAD(); 100 PRCondVar* cvar; 101 PRThreadPriority pri; 102 103 if (!_PR_IS_NATIVE_THREAD(me)) { 104 PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); 105 } 106 107 cvar = thread->wait.cvar; 108 thread->wait.cvar = NULL; 109 _PR_THREAD_UNLOCK(thread); 110 111 _PR_CVAR_LOCK(cvar); 112 _PR_THREAD_LOCK(thread); 113 114 if (!_PR_IS_NATIVE_THREAD(thread)) { 115 _PR_SLEEPQ_LOCK(thread->cpu); 116 /* The notify and timeout can collide; in which case both may 117 * attempt to delete from the sleepQ; only let one do it. 118 */ 119 if (thread->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)) { 120 _PR_DEL_SLEEPQ(thread, PR_TRUE); 121 } 122 _PR_SLEEPQ_UNLOCK(thread->cpu); 123 124 /* Make thread runnable */ 125 pri = thread->priority; 126 thread->state = _PR_RUNNABLE; 127 128 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 129 130 _PR_AddThreadToRunQ(me, thread); 131 _PR_THREAD_UNLOCK(thread); 132 133 _PR_MD_WAKEUP_WAITER(thread); 134 } else { 135 if (thread->flags & _PR_SUSPENDING) { 136 /* 137 * set thread state to SUSPENDED; a Resume operation 138 * on the thread will enable the thread to run 139 */ 140 thread->state = _PR_SUSPENDED; 141 } else { 142 thread->state = _PR_RUNNING; 143 } 144 _PR_THREAD_UNLOCK(thread); 145 _PR_MD_WAKEUP_WAITER(thread); 146 } 147 148 _PR_CVAR_UNLOCK(cvar); 149 return; 150 } 151 152 /* 153 ** Make the given thread wait for the given condition variable 154 */ 155 PRStatus _PR_WaitCondVar(PRThread* thread, PRCondVar* cvar, PRLock* lock, 156 PRIntervalTime timeout) { 157 PRIntn is; 158 PRStatus rv = PR_SUCCESS; 159 160 PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); 161 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 162 163 #ifdef _PR_GLOBAL_THREADS_ONLY 164 if (_PR_PENDING_INTERRUPT(thread)) { 165 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 166 thread->flags &= ~_PR_INTERRUPT; 167 return PR_FAILURE; 168 } 169 170 thread->wait.cvar = cvar; 171 lock->owner = NULL; 172 _PR_MD_WAIT_CV(&cvar->md, &lock->ilock, timeout); 173 thread->wait.cvar = NULL; 174 lock->owner = thread; 175 if (_PR_PENDING_INTERRUPT(thread)) { 176 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 177 thread->flags &= ~_PR_INTERRUPT; 178 return PR_FAILURE; 179 } 180 181 return PR_SUCCESS; 182 #else /* _PR_GLOBAL_THREADS_ONLY */ 183 184 if (!_PR_IS_NATIVE_THREAD(thread)) { 185 _PR_INTSOFF(is); 186 } 187 188 _PR_CVAR_LOCK(cvar); 189 _PR_THREAD_LOCK(thread); 190 191 if (_PR_PENDING_INTERRUPT(thread)) { 192 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 193 thread->flags &= ~_PR_INTERRUPT; 194 _PR_CVAR_UNLOCK(cvar); 195 _PR_THREAD_UNLOCK(thread); 196 if (!_PR_IS_NATIVE_THREAD(thread)) { 197 _PR_INTSON(is); 198 } 199 return PR_FAILURE; 200 } 201 202 thread->state = _PR_COND_WAIT; 203 thread->wait.cvar = cvar; 204 205 /* 206 ** Put the caller thread on the condition variable's wait Q 207 */ 208 PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ); 209 210 /* Note- for global scope threads, we don't put them on the 211 * global sleepQ, so each global thread must put itself 212 * to sleep only for the time it wants to. 213 */ 214 if (!_PR_IS_NATIVE_THREAD(thread)) { 215 _PR_SLEEPQ_LOCK(thread->cpu); 216 _PR_ADD_SLEEPQ(thread, timeout); 217 _PR_SLEEPQ_UNLOCK(thread->cpu); 218 } 219 _PR_CVAR_UNLOCK(cvar); 220 _PR_THREAD_UNLOCK(thread); 221 222 /* 223 ** Release lock protecting the condition variable and thereby giving time 224 ** to the next thread which can potentially notify on the condition variable 225 */ 226 PR_Unlock(lock); 227 228 PR_LOG(_pr_cvar_lm, PR_LOG_MIN, 229 ("PR_Wait: cvar=%p waiting for %d", cvar, timeout)); 230 231 rv = _PR_MD_WAIT(thread, timeout); 232 233 _PR_CVAR_LOCK(cvar); 234 PR_REMOVE_LINK(&thread->waitQLinks); 235 _PR_CVAR_UNLOCK(cvar); 236 237 PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_Wait: cvar=%p done waiting", cvar)); 238 239 if (!_PR_IS_NATIVE_THREAD(thread)) { 240 _PR_INTSON(is); 241 } 242 243 /* Acquire lock again that we had just relinquished */ 244 PR_Lock(lock); 245 246 if (_PR_PENDING_INTERRUPT(thread)) { 247 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 248 thread->flags &= ~_PR_INTERRUPT; 249 return PR_FAILURE; 250 } 251 252 return rv; 253 #endif /* _PR_GLOBAL_THREADS_ONLY */ 254 } 255 256 void _PR_NotifyCondVar(PRCondVar* cvar, PRThread* me) { 257 #ifdef _PR_GLOBAL_THREADS_ONLY 258 _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock); 259 #else /* _PR_GLOBAL_THREADS_ONLY */ 260 261 PRCList* q; 262 PRIntn is; 263 264 if (!_PR_IS_NATIVE_THREAD(me)) { 265 _PR_INTSOFF(is); 266 } 267 PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); 268 269 _PR_CVAR_LOCK(cvar); 270 q = cvar->condQ.next; 271 while (q != &cvar->condQ) { 272 PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar)); 273 if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar) { 274 if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE) { 275 break; 276 } 277 } 278 q = q->next; 279 } 280 _PR_CVAR_UNLOCK(cvar); 281 282 if (!_PR_IS_NATIVE_THREAD(me)) { 283 _PR_INTSON(is); 284 } 285 286 #endif /* _PR_GLOBAL_THREADS_ONLY */ 287 } 288 289 /* 290 ** Cndition variable debugging log info. 291 */ 292 PRUint32 _PR_CondVarToString(PRCondVar* cvar, char* buf, PRUint32 buflen) { 293 PRUint32 nb; 294 295 if (cvar->lock->owner) { 296 nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]", cvar, 297 cvar->lock->owner->id, cvar->lock->owner); 298 } else { 299 nb = PR_snprintf(buf, buflen, "[%p]", cvar); 300 } 301 return nb; 302 } 303 304 /* 305 ** Expire condition variable waits that are ready to expire. "now" is the 306 *current 307 ** time. 308 */ 309 void _PR_ClockInterrupt(void) { 310 PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); 311 _PRCPU* cpu = me->cpu; 312 PRIntervalTime elapsed, now; 313 314 PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); 315 /* Figure out how much time elapsed since the last clock tick */ 316 now = PR_IntervalNow(); 317 elapsed = now - cpu->last_clock; 318 cpu->last_clock = now; 319 320 PR_LOG(_pr_clock_lm, PR_LOG_MAX, ("ExpireWaits: elapsed=%lld usec", elapsed)); 321 322 while (1) { 323 _PR_SLEEPQ_LOCK(cpu); 324 if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) { 325 _PR_SLEEPQ_UNLOCK(cpu); 326 break; 327 } 328 329 thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next); 330 PR_ASSERT(thread->cpu == cpu); 331 332 if (elapsed < thread->sleep) { 333 thread->sleep -= elapsed; 334 _PR_SLEEPQMAX(thread->cpu) -= elapsed; 335 _PR_SLEEPQ_UNLOCK(cpu); 336 break; 337 } 338 _PR_SLEEPQ_UNLOCK(cpu); 339 340 PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); 341 342 _PR_THREAD_LOCK(thread); 343 344 if (thread->cpu != cpu) { 345 /* 346 ** The thread was switched to another CPU 347 ** between the time we unlocked the sleep 348 ** queue and the time we acquired the thread 349 ** lock, so it is none of our business now. 350 */ 351 _PR_THREAD_UNLOCK(thread); 352 continue; 353 } 354 355 /* 356 ** Consume this sleeper's amount of elapsed time from the elapsed 357 ** time value. The next remaining piece of elapsed time will be 358 ** available for the next sleeping thread's timer. 359 */ 360 _PR_SLEEPQ_LOCK(cpu); 361 PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ)); 362 if (thread->flags & _PR_ON_SLEEPQ) { 363 _PR_DEL_SLEEPQ(thread, PR_FALSE); 364 elapsed -= thread->sleep; 365 _PR_SLEEPQ_UNLOCK(cpu); 366 } else { 367 /* Thread was already handled; Go get another one */ 368 _PR_SLEEPQ_UNLOCK(cpu); 369 _PR_THREAD_UNLOCK(thread); 370 continue; 371 } 372 373 /* Notify the thread waiting on the condition variable */ 374 if (thread->flags & _PR_SUSPENDING) { 375 PR_ASSERT((thread->state == _PR_IO_WAIT) || 376 (thread->state == _PR_COND_WAIT)); 377 /* 378 ** Thread is suspended and its condition timeout 379 ** expired. Transfer thread from sleepQ to suspendQ. 380 */ 381 thread->wait.cvar = NULL; 382 _PR_MISCQ_LOCK(cpu); 383 thread->state = _PR_SUSPENDED; 384 _PR_ADD_SUSPENDQ(thread, cpu); 385 _PR_MISCQ_UNLOCK(cpu); 386 } else { 387 if (thread->wait.cvar) { 388 PRThreadPriority pri; 389 390 /* Do work very similar to what _PR_NotifyThread does */ 391 PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); 392 393 /* Make thread runnable */ 394 pri = thread->priority; 395 thread->state = _PR_RUNNABLE; 396 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 397 398 PR_ASSERT(thread->cpu == cpu); 399 _PR_RUNQ_LOCK(cpu); 400 _PR_ADD_RUNQ(thread, cpu, pri); 401 _PR_RUNQ_UNLOCK(cpu); 402 403 if (pri > me->priority) { 404 _PR_SET_RESCHED_FLAG(); 405 } 406 407 thread->wait.cvar = NULL; 408 409 _PR_MD_WAKEUP_WAITER(thread); 410 411 } else if (thread->io_pending == PR_TRUE) { 412 /* Need to put IO sleeper back on runq */ 413 int pri = thread->priority; 414 415 thread->io_suspended = PR_TRUE; 416 #ifdef WINNT 417 /* 418 * For NT, record the cpu on which I/O was issued 419 * I/O cancellation is done on the same cpu 420 */ 421 thread->md.thr_bound_cpu = cpu; 422 #endif 423 424 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 425 PR_ASSERT(thread->cpu == cpu); 426 thread->state = _PR_RUNNABLE; 427 _PR_RUNQ_LOCK(cpu); 428 _PR_ADD_RUNQ(thread, cpu, pri); 429 _PR_RUNQ_UNLOCK(cpu); 430 } 431 } 432 _PR_THREAD_UNLOCK(thread); 433 } 434 } 435 436 /************************************************************************/ 437 438 /* 439 ** Create a new condition variable. 440 ** "lock" is the lock to use with the condition variable. 441 ** 442 ** Condition variables are synchronization objects that threads can use 443 ** to wait for some condition to occur. 444 ** 445 ** This may fail if memory is tight or if some operating system resource 446 ** is low. 447 */ 448 PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock* lock) { 449 PRCondVar* cvar; 450 451 cvar = PR_NEWZAP(PRCondVar); 452 if (cvar) { 453 if (_PR_InitCondVar(cvar, lock) != PR_SUCCESS) { 454 PR_DELETE(cvar); 455 return NULL; 456 } 457 } else { 458 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 459 } 460 return cvar; 461 } 462 463 PRStatus _PR_InitCondVar(PRCondVar* cvar, PRLock* lock) { 464 PR_ASSERT(lock != NULL); 465 466 #ifdef _PR_GLOBAL_THREADS_ONLY 467 if (_PR_MD_NEW_CV(&cvar->md)) { 468 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 469 return PR_FAILURE; 470 } 471 #endif 472 if (_PR_MD_NEW_LOCK(&(cvar->ilock)) != PR_SUCCESS) { 473 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 474 return PR_FAILURE; 475 } 476 cvar->lock = lock; 477 PR_INIT_CLIST(&cvar->condQ); 478 return PR_SUCCESS; 479 } 480 481 /* 482 ** Destroy a condition variable. There must be no thread 483 ** waiting on the condvar. The caller is responsible for guaranteeing 484 ** that the condvar is no longer in use. 485 ** 486 */ 487 PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar* cvar) { 488 _PR_FreeCondVar(cvar); 489 PR_DELETE(cvar); 490 } 491 492 void _PR_FreeCondVar(PRCondVar* cvar) { 493 PR_ASSERT(cvar->condQ.next == &cvar->condQ); 494 495 #ifdef _PR_GLOBAL_THREADS_ONLY 496 _PR_MD_FREE_CV(&cvar->md); 497 #endif 498 _PR_MD_FREE_LOCK(&(cvar->ilock)); 499 } 500 501 /* 502 ** Wait for a notify on the condition variable. Sleep for "tiemout" amount 503 ** of ticks (if "timeout" is zero then the sleep is indefinite). While 504 ** the thread is waiting it unlocks lock. When the wait has 505 ** finished the thread regains control of the condition variable after 506 ** locking the associated lock. 507 ** 508 ** The thread waiting on the condvar will be resumed when the condvar is 509 ** notified (assuming the thread is the next in line to receive the 510 ** notify) or when the timeout elapses. 511 ** 512 ** Returns PR_FAILURE if the caller has not locked the lock associated 513 ** with the condition variable or the thread has been interrupted. 514 */ 515 extern PRThread* suspendAllThread; 516 PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar* cvar, PRIntervalTime timeout) { 517 PRThread* me = _PR_MD_CURRENT_THREAD(); 518 519 PR_ASSERT(cvar->lock->owner == me); 520 PR_ASSERT(me != suspendAllThread); 521 if (cvar->lock->owner != me) { 522 return PR_FAILURE; 523 } 524 525 return _PR_WaitCondVar(me, cvar, cvar->lock, timeout); 526 } 527 528 /* 529 ** Notify the highest priority thread waiting on the condition 530 ** variable. If a thread is waiting on the condition variable (using 531 ** PR_Wait) then it is awakened and begins waiting on the lock. 532 */ 533 PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar* cvar) { 534 PRThread* me = _PR_MD_CURRENT_THREAD(); 535 536 PR_ASSERT(cvar->lock->owner == me); 537 PR_ASSERT(me != suspendAllThread); 538 if (cvar->lock->owner != me) { 539 return PR_FAILURE; 540 } 541 542 _PR_NotifyCondVar(cvar, me); 543 return PR_SUCCESS; 544 } 545 546 /* 547 ** Notify all of the threads waiting on the condition variable. All of 548 ** threads are notified in turn. The highest priority thread will 549 ** probably acquire the lock. 550 */ 551 PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar* cvar) { 552 PRCList* q; 553 PRIntn is; 554 PRThread* me = _PR_MD_CURRENT_THREAD(); 555 556 PR_ASSERT(cvar->lock->owner == me); 557 if (cvar->lock->owner != me) { 558 return PR_FAILURE; 559 } 560 561 #ifdef _PR_GLOBAL_THREADS_ONLY 562 _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock); 563 return PR_SUCCESS; 564 #else /* _PR_GLOBAL_THREADS_ONLY */ 565 if (!_PR_IS_NATIVE_THREAD(me)) { 566 _PR_INTSOFF(is); 567 } 568 _PR_CVAR_LOCK(cvar); 569 q = cvar->condQ.next; 570 while (q != &cvar->condQ) { 571 PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); 572 _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); 573 q = q->next; 574 } 575 _PR_CVAR_UNLOCK(cvar); 576 if (!_PR_IS_NATIVE_THREAD(me)) { 577 _PR_INTSON(is); 578 } 579 580 return PR_SUCCESS; 581 #endif /* _PR_GLOBAL_THREADS_ONLY */ 582 } 583 584 /*********************************************************************/ 585 /*********************************************************************/ 586 /********************ROUTINES FOR DCE EMULATION***********************/ 587 /*********************************************************************/ 588 /*********************************************************************/ 589 #include "prpdce.h" 590 591 PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) { 592 PRCondVar* cvar = PR_NEWZAP(PRCondVar); 593 if (NULL != cvar) { 594 if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) { 595 PR_DELETE(cvar); 596 cvar = NULL; 597 } else { 598 PR_INIT_CLIST(&cvar->condQ); 599 cvar->lock = _PR_NAKED_CV_LOCK; 600 } 601 } 602 return cvar; 603 } 604 605 PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar* cvar) { 606 PR_ASSERT(cvar->condQ.next == &cvar->condQ); 607 PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); 608 609 _PR_MD_FREE_LOCK(&(cvar->ilock)); 610 611 PR_DELETE(cvar); 612 } 613 614 PR_IMPLEMENT(PRStatus) 615 PRP_NakedWait(PRCondVar* cvar, PRLock* lock, PRIntervalTime timeout) { 616 PRThread* me = _PR_MD_CURRENT_THREAD(); 617 PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); 618 return _PR_WaitCondVar(me, cvar, lock, timeout); 619 } /* PRP_NakedWait */ 620 621 PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar* cvar) { 622 PRThread* me = _PR_MD_CURRENT_THREAD(); 623 PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); 624 625 _PR_NotifyCondVar(cvar, me); 626 627 return PR_SUCCESS; 628 } /* PRP_NakedNotify */ 629 630 PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar* cvar) { 631 PRCList* q; 632 PRIntn is; 633 PRThread* me = _PR_MD_CURRENT_THREAD(); 634 PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); 635 636 if (!_PR_IS_NATIVE_THREAD(me)) { 637 _PR_INTSOFF(is); 638 } 639 _PR_MD_LOCK(&(cvar->ilock)); 640 q = cvar->condQ.next; 641 while (q != &cvar->condQ) { 642 PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); 643 _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); 644 q = q->next; 645 } 646 _PR_MD_UNLOCK(&(cvar->ilock)); 647 if (!_PR_IS_NATIVE_THREAD(me)) { 648 _PR_INTSON(is); 649 } 650 651 return PR_SUCCESS; 652 } /* PRP_NakedBroadcast */