1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/threads/combined/prucv.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,655 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 + 1.10 +#include "primpl.h" 1.11 +#include "prinrval.h" 1.12 +#include "prtypes.h" 1.13 + 1.14 +#if defined(WIN95) 1.15 +/* 1.16 +** Some local variables report warnings on Win95 because the code paths 1.17 +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. 1.18 +** The pragma suppresses the warning. 1.19 +** 1.20 +*/ 1.21 +#pragma warning(disable : 4101) 1.22 +#endif 1.23 + 1.24 + 1.25 +/* 1.26 +** Notify one thread that it has finished waiting on a condition variable 1.27 +** Caller must hold the _PR_CVAR_LOCK(cv) 1.28 +*/ 1.29 +PRBool _PR_NotifyThread (PRThread *thread, PRThread *me) 1.30 +{ 1.31 + PRBool rv; 1.32 + 1.33 + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); 1.34 + 1.35 + _PR_THREAD_LOCK(thread); 1.36 + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 1.37 + if ( !_PR_IS_NATIVE_THREAD(thread) ) { 1.38 + if (thread->wait.cvar != NULL) { 1.39 + thread->wait.cvar = NULL; 1.40 + 1.41 + _PR_SLEEPQ_LOCK(thread->cpu); 1.42 + /* The notify and timeout can collide; in which case both may 1.43 + * attempt to delete from the sleepQ; only let one do it. 1.44 + */ 1.45 + if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) 1.46 + _PR_DEL_SLEEPQ(thread, PR_TRUE); 1.47 + _PR_SLEEPQ_UNLOCK(thread->cpu); 1.48 + 1.49 + if (thread->flags & _PR_SUSPENDING) { 1.50 + /* 1.51 + * set thread state to SUSPENDED; a Resume operation 1.52 + * on the thread will move it to the runQ 1.53 + */ 1.54 + thread->state = _PR_SUSPENDED; 1.55 + _PR_MISCQ_LOCK(thread->cpu); 1.56 + _PR_ADD_SUSPENDQ(thread, thread->cpu); 1.57 + _PR_MISCQ_UNLOCK(thread->cpu); 1.58 + _PR_THREAD_UNLOCK(thread); 1.59 + } else { 1.60 + /* Make thread runnable */ 1.61 + thread->state = _PR_RUNNABLE; 1.62 + _PR_THREAD_UNLOCK(thread); 1.63 + 1.64 + _PR_AddThreadToRunQ(me, thread); 1.65 + _PR_MD_WAKEUP_WAITER(thread); 1.66 + } 1.67 + 1.68 + rv = PR_TRUE; 1.69 + } else { 1.70 + /* Thread has already been notified */ 1.71 + _PR_THREAD_UNLOCK(thread); 1.72 + rv = PR_FALSE; 1.73 + } 1.74 + } else { /* If the thread is a native thread */ 1.75 + if (thread->wait.cvar) { 1.76 + thread->wait.cvar = NULL; 1.77 + 1.78 + if (thread->flags & _PR_SUSPENDING) { 1.79 + /* 1.80 + * set thread state to SUSPENDED; a Resume operation 1.81 + * on the thread will enable the thread to run 1.82 + */ 1.83 + thread->state = _PR_SUSPENDED; 1.84 + } else 1.85 + thread->state = _PR_RUNNING; 1.86 + _PR_THREAD_UNLOCK(thread); 1.87 + _PR_MD_WAKEUP_WAITER(thread); 1.88 + rv = PR_TRUE; 1.89 + } else { 1.90 + _PR_THREAD_UNLOCK(thread); 1.91 + rv = PR_FALSE; 1.92 + } 1.93 + } 1.94 + 1.95 + return rv; 1.96 +} 1.97 + 1.98 +/* 1.99 + * Notify thread waiting on cvar; called when thread is interrupted 1.100 + * The thread lock is held on entry and released before return 1.101 + */ 1.102 +void _PR_NotifyLockedThread (PRThread *thread) 1.103 +{ 1.104 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.105 + PRCondVar *cvar; 1.106 + PRThreadPriority pri; 1.107 + 1.108 + if ( !_PR_IS_NATIVE_THREAD(me)) 1.109 + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); 1.110 + 1.111 + cvar = thread->wait.cvar; 1.112 + thread->wait.cvar = NULL; 1.113 + _PR_THREAD_UNLOCK(thread); 1.114 + 1.115 + _PR_CVAR_LOCK(cvar); 1.116 + _PR_THREAD_LOCK(thread); 1.117 + 1.118 + if (!_PR_IS_NATIVE_THREAD(thread)) { 1.119 + _PR_SLEEPQ_LOCK(thread->cpu); 1.120 + /* The notify and timeout can collide; in which case both may 1.121 + * attempt to delete from the sleepQ; only let one do it. 1.122 + */ 1.123 + if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) 1.124 + _PR_DEL_SLEEPQ(thread, PR_TRUE); 1.125 + _PR_SLEEPQ_UNLOCK(thread->cpu); 1.126 + 1.127 + /* Make thread runnable */ 1.128 + pri = thread->priority; 1.129 + thread->state = _PR_RUNNABLE; 1.130 + 1.131 + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 1.132 + 1.133 + _PR_AddThreadToRunQ(me, thread); 1.134 + _PR_THREAD_UNLOCK(thread); 1.135 + 1.136 + _PR_MD_WAKEUP_WAITER(thread); 1.137 + } else { 1.138 + if (thread->flags & _PR_SUSPENDING) { 1.139 + /* 1.140 + * set thread state to SUSPENDED; a Resume operation 1.141 + * on the thread will enable the thread to run 1.142 + */ 1.143 + thread->state = _PR_SUSPENDED; 1.144 + } else 1.145 + thread->state = _PR_RUNNING; 1.146 + _PR_THREAD_UNLOCK(thread); 1.147 + _PR_MD_WAKEUP_WAITER(thread); 1.148 + } 1.149 + 1.150 + _PR_CVAR_UNLOCK(cvar); 1.151 + return; 1.152 +} 1.153 + 1.154 +/* 1.155 +** Make the given thread wait for the given condition variable 1.156 +*/ 1.157 +PRStatus _PR_WaitCondVar( 1.158 + PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) 1.159 +{ 1.160 + PRIntn is; 1.161 + PRStatus rv = PR_SUCCESS; 1.162 + 1.163 + PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); 1.164 + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 1.165 + 1.166 +#ifdef _PR_GLOBAL_THREADS_ONLY 1.167 + if (_PR_PENDING_INTERRUPT(thread)) { 1.168 + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1.169 + thread->flags &= ~_PR_INTERRUPT; 1.170 + return PR_FAILURE; 1.171 + } 1.172 + 1.173 + thread->wait.cvar = cvar; 1.174 + lock->owner = NULL; 1.175 + _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout); 1.176 + thread->wait.cvar = NULL; 1.177 + lock->owner = thread; 1.178 + if (_PR_PENDING_INTERRUPT(thread)) { 1.179 + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1.180 + thread->flags &= ~_PR_INTERRUPT; 1.181 + return PR_FAILURE; 1.182 + } 1.183 + 1.184 + return PR_SUCCESS; 1.185 +#else /* _PR_GLOBAL_THREADS_ONLY */ 1.186 + 1.187 + if ( !_PR_IS_NATIVE_THREAD(thread)) 1.188 + _PR_INTSOFF(is); 1.189 + 1.190 + _PR_CVAR_LOCK(cvar); 1.191 + _PR_THREAD_LOCK(thread); 1.192 + 1.193 + if (_PR_PENDING_INTERRUPT(thread)) { 1.194 + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1.195 + thread->flags &= ~_PR_INTERRUPT; 1.196 + _PR_CVAR_UNLOCK(cvar); 1.197 + _PR_THREAD_UNLOCK(thread); 1.198 + if ( !_PR_IS_NATIVE_THREAD(thread)) 1.199 + _PR_INTSON(is); 1.200 + return PR_FAILURE; 1.201 + } 1.202 + 1.203 + thread->state = _PR_COND_WAIT; 1.204 + thread->wait.cvar = cvar; 1.205 + 1.206 + /* 1.207 + ** Put the caller thread on the condition variable's wait Q 1.208 + */ 1.209 + PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ); 1.210 + 1.211 + /* Note- for global scope threads, we don't put them on the 1.212 + * global sleepQ, so each global thread must put itself 1.213 + * to sleep only for the time it wants to. 1.214 + */ 1.215 + if ( !_PR_IS_NATIVE_THREAD(thread) ) { 1.216 + _PR_SLEEPQ_LOCK(thread->cpu); 1.217 + _PR_ADD_SLEEPQ(thread, timeout); 1.218 + _PR_SLEEPQ_UNLOCK(thread->cpu); 1.219 + } 1.220 + _PR_CVAR_UNLOCK(cvar); 1.221 + _PR_THREAD_UNLOCK(thread); 1.222 + 1.223 + /* 1.224 + ** Release lock protecting the condition variable and thereby giving time 1.225 + ** to the next thread which can potentially notify on the condition variable 1.226 + */ 1.227 + PR_Unlock(lock); 1.228 + 1.229 + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, 1.230 + ("PR_Wait: cvar=%p waiting for %d", cvar, timeout)); 1.231 + 1.232 + rv = _PR_MD_WAIT(thread, timeout); 1.233 + 1.234 + _PR_CVAR_LOCK(cvar); 1.235 + PR_REMOVE_LINK(&thread->waitQLinks); 1.236 + _PR_CVAR_UNLOCK(cvar); 1.237 + 1.238 + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, 1.239 + ("PR_Wait: cvar=%p done waiting", cvar)); 1.240 + 1.241 + if ( !_PR_IS_NATIVE_THREAD(thread)) 1.242 + _PR_INTSON(is); 1.243 + 1.244 + /* Acquire lock again that we had just relinquished */ 1.245 + PR_Lock(lock); 1.246 + 1.247 + if (_PR_PENDING_INTERRUPT(thread)) { 1.248 + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1.249 + thread->flags &= ~_PR_INTERRUPT; 1.250 + return PR_FAILURE; 1.251 + } 1.252 + 1.253 + return rv; 1.254 +#endif /* _PR_GLOBAL_THREADS_ONLY */ 1.255 +} 1.256 + 1.257 +void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me) 1.258 +{ 1.259 +#ifdef _PR_GLOBAL_THREADS_ONLY 1.260 + _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock); 1.261 +#else /* _PR_GLOBAL_THREADS_ONLY */ 1.262 + 1.263 + PRCList *q; 1.264 + PRIntn is; 1.265 + 1.266 + if ( !_PR_IS_NATIVE_THREAD(me)) 1.267 + _PR_INTSOFF(is); 1.268 + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); 1.269 + 1.270 + _PR_CVAR_LOCK(cvar); 1.271 + q = cvar->condQ.next; 1.272 + while (q != &cvar->condQ) { 1.273 + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar)); 1.274 + if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar) { 1.275 + if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE) 1.276 + break; 1.277 + } 1.278 + q = q->next; 1.279 + } 1.280 + _PR_CVAR_UNLOCK(cvar); 1.281 + 1.282 + if ( !_PR_IS_NATIVE_THREAD(me)) 1.283 + _PR_INTSON(is); 1.284 + 1.285 +#endif /* _PR_GLOBAL_THREADS_ONLY */ 1.286 +} 1.287 + 1.288 +/* 1.289 +** Cndition variable debugging log info. 1.290 +*/ 1.291 +PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen) 1.292 +{ 1.293 + PRUint32 nb; 1.294 + 1.295 + if (cvar->lock->owner) { 1.296 + nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]", 1.297 + cvar, cvar->lock->owner->id, cvar->lock->owner); 1.298 + } else { 1.299 + nb = PR_snprintf(buf, buflen, "[%p]", cvar); 1.300 + } 1.301 + return nb; 1.302 +} 1.303 + 1.304 +/* 1.305 +** Expire condition variable waits that are ready to expire. "now" is the current 1.306 +** time. 1.307 +*/ 1.308 +void _PR_ClockInterrupt(void) 1.309 +{ 1.310 + PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); 1.311 + _PRCPU *cpu = me->cpu; 1.312 + PRIntervalTime elapsed, now; 1.313 + 1.314 + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); 1.315 + /* Figure out how much time elapsed since the last clock tick */ 1.316 + now = PR_IntervalNow(); 1.317 + elapsed = now - cpu->last_clock; 1.318 + cpu->last_clock = now; 1.319 + 1.320 + PR_LOG(_pr_clock_lm, PR_LOG_MAX, 1.321 + ("ExpireWaits: elapsed=%lld usec", elapsed)); 1.322 + 1.323 + while(1) { 1.324 + _PR_SLEEPQ_LOCK(cpu); 1.325 + if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) { 1.326 + _PR_SLEEPQ_UNLOCK(cpu); 1.327 + break; 1.328 + } 1.329 + 1.330 + thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next); 1.331 + PR_ASSERT(thread->cpu == cpu); 1.332 + 1.333 + if (elapsed < thread->sleep) { 1.334 + thread->sleep -= elapsed; 1.335 + _PR_SLEEPQMAX(thread->cpu) -= elapsed; 1.336 + _PR_SLEEPQ_UNLOCK(cpu); 1.337 + break; 1.338 + } 1.339 + _PR_SLEEPQ_UNLOCK(cpu); 1.340 + 1.341 + PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); 1.342 + 1.343 + _PR_THREAD_LOCK(thread); 1.344 + 1.345 + if (thread->cpu != cpu) { 1.346 + /* 1.347 + ** The thread was switched to another CPU 1.348 + ** between the time we unlocked the sleep 1.349 + ** queue and the time we acquired the thread 1.350 + ** lock, so it is none of our business now. 1.351 + */ 1.352 + _PR_THREAD_UNLOCK(thread); 1.353 + continue; 1.354 + } 1.355 + 1.356 + /* 1.357 + ** Consume this sleeper's amount of elapsed time from the elapsed 1.358 + ** time value. The next remaining piece of elapsed time will be 1.359 + ** available for the next sleeping thread's timer. 1.360 + */ 1.361 + _PR_SLEEPQ_LOCK(cpu); 1.362 + PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ)); 1.363 + if (thread->flags & _PR_ON_SLEEPQ) { 1.364 + _PR_DEL_SLEEPQ(thread, PR_FALSE); 1.365 + elapsed -= thread->sleep; 1.366 + _PR_SLEEPQ_UNLOCK(cpu); 1.367 + } else { 1.368 + /* Thread was already handled; Go get another one */ 1.369 + _PR_SLEEPQ_UNLOCK(cpu); 1.370 + _PR_THREAD_UNLOCK(thread); 1.371 + continue; 1.372 + } 1.373 + 1.374 + /* Notify the thread waiting on the condition variable */ 1.375 + if (thread->flags & _PR_SUSPENDING) { 1.376 + PR_ASSERT((thread->state == _PR_IO_WAIT) || 1.377 + (thread->state == _PR_COND_WAIT)); 1.378 + /* 1.379 + ** Thread is suspended and its condition timeout 1.380 + ** expired. Transfer thread from sleepQ to suspendQ. 1.381 + */ 1.382 + thread->wait.cvar = NULL; 1.383 + _PR_MISCQ_LOCK(cpu); 1.384 + thread->state = _PR_SUSPENDED; 1.385 + _PR_ADD_SUSPENDQ(thread, cpu); 1.386 + _PR_MISCQ_UNLOCK(cpu); 1.387 + } else { 1.388 + if (thread->wait.cvar) { 1.389 + PRThreadPriority pri; 1.390 + 1.391 + /* Do work very similar to what _PR_NotifyThread does */ 1.392 + PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) ); 1.393 + 1.394 + /* Make thread runnable */ 1.395 + pri = thread->priority; 1.396 + thread->state = _PR_RUNNABLE; 1.397 + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 1.398 + 1.399 + PR_ASSERT(thread->cpu == cpu); 1.400 + _PR_RUNQ_LOCK(cpu); 1.401 + _PR_ADD_RUNQ(thread, cpu, pri); 1.402 + _PR_RUNQ_UNLOCK(cpu); 1.403 + 1.404 + if (pri > me->priority) 1.405 + _PR_SET_RESCHED_FLAG(); 1.406 + 1.407 + thread->wait.cvar = NULL; 1.408 + 1.409 + _PR_MD_WAKEUP_WAITER(thread); 1.410 + 1.411 + } else if (thread->io_pending == PR_TRUE) { 1.412 + /* Need to put IO sleeper back on runq */ 1.413 + int pri = thread->priority; 1.414 + 1.415 + thread->io_suspended = PR_TRUE; 1.416 +#ifdef WINNT 1.417 + /* 1.418 + * For NT, record the cpu on which I/O was issued 1.419 + * I/O cancellation is done on the same cpu 1.420 + */ 1.421 + thread->md.thr_bound_cpu = cpu; 1.422 +#endif 1.423 + 1.424 + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); 1.425 + PR_ASSERT(thread->cpu == cpu); 1.426 + thread->state = _PR_RUNNABLE; 1.427 + _PR_RUNQ_LOCK(cpu); 1.428 + _PR_ADD_RUNQ(thread, cpu, pri); 1.429 + _PR_RUNQ_UNLOCK(cpu); 1.430 + } 1.431 + } 1.432 + _PR_THREAD_UNLOCK(thread); 1.433 + } 1.434 +} 1.435 + 1.436 +/************************************************************************/ 1.437 + 1.438 +/* 1.439 +** Create a new condition variable. 1.440 +** "lock" is the lock to use with the condition variable. 1.441 +** 1.442 +** Condition variables are synchronization objects that threads can use 1.443 +** to wait for some condition to occur. 1.444 +** 1.445 +** This may fail if memory is tight or if some operating system resource 1.446 +** is low. 1.447 +*/ 1.448 +PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) 1.449 +{ 1.450 + PRCondVar *cvar; 1.451 + 1.452 + cvar = PR_NEWZAP(PRCondVar); 1.453 + if (cvar) { 1.454 + if (_PR_InitCondVar(cvar, lock) != PR_SUCCESS) { 1.455 + PR_DELETE(cvar); 1.456 + return NULL; 1.457 + } 1.458 + } else { 1.459 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.460 + } 1.461 + return cvar; 1.462 +} 1.463 + 1.464 +PRStatus _PR_InitCondVar(PRCondVar *cvar, PRLock *lock) 1.465 +{ 1.466 + PR_ASSERT(lock != NULL); 1.467 + 1.468 +#ifdef _PR_GLOBAL_THREADS_ONLY 1.469 + if(_PR_MD_NEW_CV(&cvar->md)) { 1.470 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1.471 + return PR_FAILURE; 1.472 + } 1.473 +#endif 1.474 + if (_PR_MD_NEW_LOCK(&(cvar->ilock)) != PR_SUCCESS) { 1.475 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); 1.476 + return PR_FAILURE; 1.477 + } 1.478 + cvar->lock = lock; 1.479 + PR_INIT_CLIST(&cvar->condQ); 1.480 + return PR_SUCCESS; 1.481 +} 1.482 + 1.483 +/* 1.484 +** Destroy a condition variable. There must be no thread 1.485 +** waiting on the condvar. The caller is responsible for guaranteeing 1.486 +** that the condvar is no longer in use. 1.487 +** 1.488 +*/ 1.489 +PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar) 1.490 +{ 1.491 + _PR_FreeCondVar(cvar); 1.492 + PR_DELETE(cvar); 1.493 +} 1.494 + 1.495 +void _PR_FreeCondVar(PRCondVar *cvar) 1.496 +{ 1.497 + PR_ASSERT(cvar->condQ.next == &cvar->condQ); 1.498 + 1.499 +#ifdef _PR_GLOBAL_THREADS_ONLY 1.500 + _PR_MD_FREE_CV(&cvar->md); 1.501 +#endif 1.502 + _PR_MD_FREE_LOCK(&(cvar->ilock)); 1.503 +} 1.504 + 1.505 +/* 1.506 +** Wait for a notify on the condition variable. Sleep for "tiemout" amount 1.507 +** of ticks (if "timeout" is zero then the sleep is indefinite). While 1.508 +** the thread is waiting it unlocks lock. When the wait has 1.509 +** finished the thread regains control of the condition variable after 1.510 +** locking the associated lock. 1.511 +** 1.512 +** The thread waiting on the condvar will be resumed when the condvar is 1.513 +** notified (assuming the thread is the next in line to receive the 1.514 +** notify) or when the timeout elapses. 1.515 +** 1.516 +** Returns PR_FAILURE if the caller has not locked the lock associated 1.517 +** with the condition variable or the thread has been interrupted. 1.518 +*/ 1.519 +extern PRThread *suspendAllThread; 1.520 +PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout) 1.521 +{ 1.522 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.523 + 1.524 + PR_ASSERT(cvar->lock->owner == me); 1.525 + PR_ASSERT(me != suspendAllThread); 1.526 + if (cvar->lock->owner != me) return PR_FAILURE; 1.527 + 1.528 + return _PR_WaitCondVar(me, cvar, cvar->lock, timeout); 1.529 +} 1.530 + 1.531 +/* 1.532 +** Notify the highest priority thread waiting on the condition 1.533 +** variable. If a thread is waiting on the condition variable (using 1.534 +** PR_Wait) then it is awakened and begins waiting on the lock. 1.535 +*/ 1.536 +PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar) 1.537 +{ 1.538 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.539 + 1.540 + PR_ASSERT(cvar->lock->owner == me); 1.541 + PR_ASSERT(me != suspendAllThread); 1.542 + if (cvar->lock->owner != me) return PR_FAILURE; 1.543 + 1.544 + _PR_NotifyCondVar(cvar, me); 1.545 + return PR_SUCCESS; 1.546 +} 1.547 + 1.548 +/* 1.549 +** Notify all of the threads waiting on the condition variable. All of 1.550 +** threads are notified in turn. The highest priority thread will 1.551 +** probably acquire the lock. 1.552 +*/ 1.553 +PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) 1.554 +{ 1.555 + PRCList *q; 1.556 + PRIntn is; 1.557 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.558 + 1.559 + PR_ASSERT(cvar->lock->owner == me); 1.560 + if (cvar->lock->owner != me) return PR_FAILURE; 1.561 + 1.562 +#ifdef _PR_GLOBAL_THREADS_ONLY 1.563 + _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock); 1.564 + return PR_SUCCESS; 1.565 +#else /* _PR_GLOBAL_THREADS_ONLY */ 1.566 + if ( !_PR_IS_NATIVE_THREAD(me)) 1.567 + _PR_INTSOFF(is); 1.568 + _PR_CVAR_LOCK(cvar); 1.569 + q = cvar->condQ.next; 1.570 + while (q != &cvar->condQ) { 1.571 + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); 1.572 + _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); 1.573 + q = q->next; 1.574 + } 1.575 + _PR_CVAR_UNLOCK(cvar); 1.576 + if (!_PR_IS_NATIVE_THREAD(me)) 1.577 + _PR_INTSON(is); 1.578 + 1.579 + return PR_SUCCESS; 1.580 +#endif /* _PR_GLOBAL_THREADS_ONLY */ 1.581 +} 1.582 + 1.583 + 1.584 +/*********************************************************************/ 1.585 +/*********************************************************************/ 1.586 +/********************ROUTINES FOR DCE EMULATION***********************/ 1.587 +/*********************************************************************/ 1.588 +/*********************************************************************/ 1.589 +#include "prpdce.h" 1.590 + 1.591 +PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) 1.592 +{ 1.593 + PRCondVar *cvar = PR_NEWZAP(PRCondVar); 1.594 + if (NULL != cvar) 1.595 + { 1.596 + if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) 1.597 + { 1.598 + PR_DELETE(cvar); cvar = NULL; 1.599 + } 1.600 + else 1.601 + { 1.602 + PR_INIT_CLIST(&cvar->condQ); 1.603 + cvar->lock = _PR_NAKED_CV_LOCK; 1.604 + } 1.605 + 1.606 + } 1.607 + return cvar; 1.608 +} 1.609 + 1.610 +PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar) 1.611 +{ 1.612 + PR_ASSERT(cvar->condQ.next == &cvar->condQ); 1.613 + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); 1.614 + 1.615 + _PR_MD_FREE_LOCK(&(cvar->ilock)); 1.616 + 1.617 + PR_DELETE(cvar); 1.618 +} 1.619 + 1.620 +PR_IMPLEMENT(PRStatus) PRP_NakedWait( 1.621 + PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) 1.622 +{ 1.623 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.624 + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); 1.625 + return _PR_WaitCondVar(me, cvar, lock, timeout); 1.626 +} /* PRP_NakedWait */ 1.627 + 1.628 +PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar) 1.629 +{ 1.630 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.631 + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); 1.632 + 1.633 + _PR_NotifyCondVar(cvar, me); 1.634 + 1.635 + return PR_SUCCESS; 1.636 +} /* PRP_NakedNotify */ 1.637 + 1.638 +PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) 1.639 +{ 1.640 + PRCList *q; 1.641 + PRIntn is; 1.642 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.643 + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); 1.644 + 1.645 + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); 1.646 + _PR_MD_LOCK( &(cvar->ilock) ); 1.647 + q = cvar->condQ.next; 1.648 + while (q != &cvar->condQ) { 1.649 + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); 1.650 + _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); 1.651 + q = q->next; 1.652 + } 1.653 + _PR_MD_UNLOCK( &(cvar->ilock) ); 1.654 + if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); 1.655 + 1.656 + return PR_SUCCESS; 1.657 +} /* PRP_NakedBroadcast */ 1.658 +