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