andre@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: andre@0: #include "primpl.h" andre@0: #include "prinrval.h" andre@0: #include "prtypes.h" andre@0: andre@0: #if defined(WIN95) andre@0: /* andre@0: ** Some local variables report warnings on Win95 because the code paths andre@0: ** using them are conditioned on HAVE_CUSTOME_USER_THREADS. andre@0: ** The pragma suppresses the warning. andre@0: ** andre@0: */ andre@0: #pragma warning(disable : 4101) andre@0: #endif andre@0: andre@0: andre@0: /* andre@0: ** Notify one thread that it has finished waiting on a condition variable andre@0: ** Caller must hold the _PR_CVAR_LOCK(cv) andre@0: */ andre@0: PRBool _PR_NotifyThread (PRThread *thread, PRThread *me) andre@0: { andre@0: PRBool rv; andre@0: andre@0: PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); andre@0: andre@0: _PR_THREAD_LOCK(thread); andre@0: PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); andre@0: if ( !_PR_IS_NATIVE_THREAD(thread) ) { andre@0: if (thread->wait.cvar != NULL) { andre@0: thread->wait.cvar = NULL; andre@0: andre@0: _PR_SLEEPQ_LOCK(thread->cpu); andre@0: /* The notify and timeout can collide; in which case both may andre@0: * attempt to delete from the sleepQ; only let one do it. andre@0: */ andre@0: if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) andre@0: _PR_DEL_SLEEPQ(thread, PR_TRUE); andre@0: _PR_SLEEPQ_UNLOCK(thread->cpu); andre@0: andre@0: if (thread->flags & _PR_SUSPENDING) { andre@0: /* andre@0: * set thread state to SUSPENDED; a Resume operation andre@0: * on the thread will move it to the runQ andre@0: */ andre@0: thread->state = _PR_SUSPENDED; andre@0: _PR_MISCQ_LOCK(thread->cpu); andre@0: _PR_ADD_SUSPENDQ(thread, thread->cpu); andre@0: _PR_MISCQ_UNLOCK(thread->cpu); andre@0: _PR_THREAD_UNLOCK(thread); andre@0: } else { andre@0: /* Make thread runnable */ andre@0: thread->state = _PR_RUNNABLE; andre@0: _PR_THREAD_UNLOCK(thread); andre@0: andre@0: _PR_AddThreadToRunQ(me, thread); andre@0: _PR_MD_WAKEUP_WAITER(thread); andre@0: } andre@0: andre@0: rv = PR_TRUE; andre@0: } else { andre@0: /* Thread has already been notified */ andre@0: _PR_THREAD_UNLOCK(thread); andre@0: rv = PR_FALSE; andre@0: } andre@0: } else { /* If the thread is a native thread */ andre@0: if (thread->wait.cvar) { andre@0: thread->wait.cvar = NULL; andre@0: andre@0: if (thread->flags & _PR_SUSPENDING) { andre@0: /* andre@0: * set thread state to SUSPENDED; a Resume operation andre@0: * on the thread will enable the thread to run andre@0: */ andre@0: thread->state = _PR_SUSPENDED; andre@0: } else andre@0: thread->state = _PR_RUNNING; andre@0: _PR_THREAD_UNLOCK(thread); andre@0: _PR_MD_WAKEUP_WAITER(thread); andre@0: rv = PR_TRUE; andre@0: } else { andre@0: _PR_THREAD_UNLOCK(thread); andre@0: rv = PR_FALSE; andre@0: } andre@0: } andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: * Notify thread waiting on cvar; called when thread is interrupted andre@0: * The thread lock is held on entry and released before return andre@0: */ andre@0: void _PR_NotifyLockedThread (PRThread *thread) andre@0: { andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PRCondVar *cvar; andre@0: PRThreadPriority pri; andre@0: andre@0: if ( !_PR_IS_NATIVE_THREAD(me)) andre@0: PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); andre@0: andre@0: cvar = thread->wait.cvar; andre@0: thread->wait.cvar = NULL; andre@0: _PR_THREAD_UNLOCK(thread); andre@0: andre@0: _PR_CVAR_LOCK(cvar); andre@0: _PR_THREAD_LOCK(thread); andre@0: andre@0: if (!_PR_IS_NATIVE_THREAD(thread)) { andre@0: _PR_SLEEPQ_LOCK(thread->cpu); andre@0: /* The notify and timeout can collide; in which case both may andre@0: * attempt to delete from the sleepQ; only let one do it. andre@0: */ andre@0: if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) andre@0: _PR_DEL_SLEEPQ(thread, PR_TRUE); andre@0: _PR_SLEEPQ_UNLOCK(thread->cpu); andre@0: andre@0: /* Make thread runnable */ andre@0: pri = thread->priority; andre@0: thread->state = _PR_RUNNABLE; andre@0: andre@0: PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); andre@0: andre@0: _PR_AddThreadToRunQ(me, thread); andre@0: _PR_THREAD_UNLOCK(thread); andre@0: andre@0: _PR_MD_WAKEUP_WAITER(thread); andre@0: } else { andre@0: if (thread->flags & _PR_SUSPENDING) { andre@0: /* andre@0: * set thread state to SUSPENDED; a Resume operation andre@0: * on the thread will enable the thread to run andre@0: */ andre@0: thread->state = _PR_SUSPENDED; andre@0: } else andre@0: thread->state = _PR_RUNNING; andre@0: _PR_THREAD_UNLOCK(thread); andre@0: _PR_MD_WAKEUP_WAITER(thread); andre@0: } andre@0: andre@0: _PR_CVAR_UNLOCK(cvar); andre@0: return; andre@0: } andre@0: andre@0: /* andre@0: ** Make the given thread wait for the given condition variable andre@0: */ andre@0: PRStatus _PR_WaitCondVar( andre@0: PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) andre@0: { andre@0: PRIntn is; andre@0: PRStatus rv = PR_SUCCESS; andre@0: andre@0: PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); andre@0: PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); andre@0: andre@0: #ifdef _PR_GLOBAL_THREADS_ONLY andre@0: if (_PR_PENDING_INTERRUPT(thread)) { andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: thread->flags &= ~_PR_INTERRUPT; andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: thread->wait.cvar = cvar; andre@0: lock->owner = NULL; andre@0: _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout); andre@0: thread->wait.cvar = NULL; andre@0: lock->owner = thread; andre@0: if (_PR_PENDING_INTERRUPT(thread)) { andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: thread->flags &= ~_PR_INTERRUPT; andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: return PR_SUCCESS; andre@0: #else /* _PR_GLOBAL_THREADS_ONLY */ andre@0: andre@0: if ( !_PR_IS_NATIVE_THREAD(thread)) andre@0: _PR_INTSOFF(is); andre@0: andre@0: _PR_CVAR_LOCK(cvar); andre@0: _PR_THREAD_LOCK(thread); andre@0: andre@0: if (_PR_PENDING_INTERRUPT(thread)) { andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: thread->flags &= ~_PR_INTERRUPT; andre@0: _PR_CVAR_UNLOCK(cvar); andre@0: _PR_THREAD_UNLOCK(thread); andre@0: if ( !_PR_IS_NATIVE_THREAD(thread)) andre@0: _PR_INTSON(is); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: thread->state = _PR_COND_WAIT; andre@0: thread->wait.cvar = cvar; andre@0: andre@0: /* andre@0: ** Put the caller thread on the condition variable's wait Q andre@0: */ andre@0: PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ); andre@0: andre@0: /* Note- for global scope threads, we don't put them on the andre@0: * global sleepQ, so each global thread must put itself andre@0: * to sleep only for the time it wants to. andre@0: */ andre@0: if ( !_PR_IS_NATIVE_THREAD(thread) ) { andre@0: _PR_SLEEPQ_LOCK(thread->cpu); andre@0: _PR_ADD_SLEEPQ(thread, timeout); andre@0: _PR_SLEEPQ_UNLOCK(thread->cpu); andre@0: } andre@0: _PR_CVAR_UNLOCK(cvar); andre@0: _PR_THREAD_UNLOCK(thread); andre@0: andre@0: /* andre@0: ** Release lock protecting the condition variable and thereby giving time andre@0: ** to the next thread which can potentially notify on the condition variable andre@0: */ andre@0: PR_Unlock(lock); andre@0: andre@0: PR_LOG(_pr_cvar_lm, PR_LOG_MIN, andre@0: ("PR_Wait: cvar=%p waiting for %d", cvar, timeout)); andre@0: andre@0: rv = _PR_MD_WAIT(thread, timeout); andre@0: andre@0: _PR_CVAR_LOCK(cvar); andre@0: PR_REMOVE_LINK(&thread->waitQLinks); andre@0: _PR_CVAR_UNLOCK(cvar); andre@0: andre@0: PR_LOG(_pr_cvar_lm, PR_LOG_MIN, andre@0: ("PR_Wait: cvar=%p done waiting", cvar)); andre@0: andre@0: if ( !_PR_IS_NATIVE_THREAD(thread)) andre@0: _PR_INTSON(is); andre@0: andre@0: /* Acquire lock again that we had just relinquished */ andre@0: PR_Lock(lock); andre@0: andre@0: if (_PR_PENDING_INTERRUPT(thread)) { andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: thread->flags &= ~_PR_INTERRUPT; andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: return rv; andre@0: #endif /* _PR_GLOBAL_THREADS_ONLY */ andre@0: } andre@0: andre@0: void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me) andre@0: { andre@0: #ifdef _PR_GLOBAL_THREADS_ONLY andre@0: _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock); andre@0: #else /* _PR_GLOBAL_THREADS_ONLY */ andre@0: andre@0: PRCList *q; andre@0: PRIntn is; andre@0: andre@0: if ( !_PR_IS_NATIVE_THREAD(me)) andre@0: _PR_INTSOFF(is); andre@0: PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); andre@0: andre@0: _PR_CVAR_LOCK(cvar); andre@0: q = cvar->condQ.next; andre@0: while (q != &cvar->condQ) { andre@0: PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar)); andre@0: if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar) { andre@0: if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE) andre@0: break; andre@0: } andre@0: q = q->next; andre@0: } andre@0: _PR_CVAR_UNLOCK(cvar); andre@0: andre@0: if ( !_PR_IS_NATIVE_THREAD(me)) andre@0: _PR_INTSON(is); andre@0: andre@0: #endif /* _PR_GLOBAL_THREADS_ONLY */ andre@0: } andre@0: andre@0: /* andre@0: ** Cndition variable debugging log info. andre@0: */ andre@0: PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen) andre@0: { andre@0: PRUint32 nb; andre@0: andre@0: if (cvar->lock->owner) { andre@0: nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]", andre@0: cvar, cvar->lock->owner->id, cvar->lock->owner); andre@0: } else { andre@0: nb = PR_snprintf(buf, buflen, "[%p]", cvar); andre@0: } andre@0: return nb; andre@0: } andre@0: andre@0: /* andre@0: ** Expire condition variable waits that are ready to expire. "now" is the current andre@0: ** time. andre@0: */ andre@0: void _PR_ClockInterrupt(void) andre@0: { andre@0: PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); andre@0: _PRCPU *cpu = me->cpu; andre@0: PRIntervalTime elapsed, now; andre@0: andre@0: PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); andre@0: /* Figure out how much time elapsed since the last clock tick */ andre@0: now = PR_IntervalNow(); andre@0: elapsed = now - cpu->last_clock; andre@0: cpu->last_clock = now; andre@0: andre@0: PR_LOG(_pr_clock_lm, PR_LOG_MAX, andre@0: ("ExpireWaits: elapsed=%lld usec", elapsed)); andre@0: andre@0: while(1) { andre@0: _PR_SLEEPQ_LOCK(cpu); andre@0: if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) { andre@0: _PR_SLEEPQ_UNLOCK(cpu); andre@0: break; andre@0: } andre@0: andre@0: thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next); andre@0: PR_ASSERT(thread->cpu == cpu); andre@0: andre@0: if (elapsed < thread->sleep) { andre@0: thread->sleep -= elapsed; andre@0: _PR_SLEEPQMAX(thread->cpu) -= elapsed; andre@0: _PR_SLEEPQ_UNLOCK(cpu); andre@0: break; andre@0: } andre@0: _PR_SLEEPQ_UNLOCK(cpu); andre@0: andre@0: PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); andre@0: andre@0: _PR_THREAD_LOCK(thread); andre@0: andre@0: if (thread->cpu != cpu) { andre@0: /* andre@0: ** The thread was switched to another CPU andre@0: ** between the time we unlocked the sleep andre@0: ** queue and the time we acquired the thread andre@0: ** lock, so it is none of our business now. andre@0: */ andre@0: _PR_THREAD_UNLOCK(thread); andre@0: continue; andre@0: } andre@0: andre@0: /* andre@0: ** Consume this sleeper's amount of elapsed time from the elapsed andre@0: ** time value. The next remaining piece of elapsed time will be andre@0: ** available for the next sleeping thread's timer. andre@0: */ andre@0: _PR_SLEEPQ_LOCK(cpu); andre@0: PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ)); andre@0: if (thread->flags & _PR_ON_SLEEPQ) { andre@0: _PR_DEL_SLEEPQ(thread, PR_FALSE); andre@0: elapsed -= thread->sleep; andre@0: _PR_SLEEPQ_UNLOCK(cpu); andre@0: } else { andre@0: /* Thread was already handled; Go get another one */ andre@0: _PR_SLEEPQ_UNLOCK(cpu); andre@0: _PR_THREAD_UNLOCK(thread); andre@0: continue; andre@0: } andre@0: andre@0: /* Notify the thread waiting on the condition variable */ andre@0: if (thread->flags & _PR_SUSPENDING) { andre@0: PR_ASSERT((thread->state == _PR_IO_WAIT) || andre@0: (thread->state == _PR_COND_WAIT)); andre@0: /* andre@0: ** Thread is suspended and its condition timeout andre@0: ** expired. Transfer thread from sleepQ to suspendQ. andre@0: */ andre@0: thread->wait.cvar = NULL; andre@0: _PR_MISCQ_LOCK(cpu); andre@0: thread->state = _PR_SUSPENDED; andre@0: _PR_ADD_SUSPENDQ(thread, cpu); andre@0: _PR_MISCQ_UNLOCK(cpu); andre@0: } else { andre@0: if (thread->wait.cvar) { andre@0: PRThreadPriority pri; andre@0: andre@0: /* Do work very similar to what _PR_NotifyThread does */ andre@0: PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) ); andre@0: andre@0: /* Make thread runnable */ andre@0: pri = thread->priority; andre@0: thread->state = _PR_RUNNABLE; andre@0: PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); andre@0: andre@0: PR_ASSERT(thread->cpu == cpu); andre@0: _PR_RUNQ_LOCK(cpu); andre@0: _PR_ADD_RUNQ(thread, cpu, pri); andre@0: _PR_RUNQ_UNLOCK(cpu); andre@0: andre@0: if (pri > me->priority) andre@0: _PR_SET_RESCHED_FLAG(); andre@0: andre@0: thread->wait.cvar = NULL; andre@0: andre@0: _PR_MD_WAKEUP_WAITER(thread); andre@0: andre@0: } else if (thread->io_pending == PR_TRUE) { andre@0: /* Need to put IO sleeper back on runq */ andre@0: int pri = thread->priority; andre@0: andre@0: thread->io_suspended = PR_TRUE; andre@0: #ifdef WINNT andre@0: /* andre@0: * For NT, record the cpu on which I/O was issued andre@0: * I/O cancellation is done on the same cpu andre@0: */ andre@0: thread->md.thr_bound_cpu = cpu; andre@0: #endif andre@0: andre@0: PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); andre@0: PR_ASSERT(thread->cpu == cpu); andre@0: thread->state = _PR_RUNNABLE; andre@0: _PR_RUNQ_LOCK(cpu); andre@0: _PR_ADD_RUNQ(thread, cpu, pri); andre@0: _PR_RUNQ_UNLOCK(cpu); andre@0: } andre@0: } andre@0: _PR_THREAD_UNLOCK(thread); andre@0: } andre@0: } andre@0: andre@0: /************************************************************************/ andre@0: andre@0: /* andre@0: ** Create a new condition variable. andre@0: ** "lock" is the lock to use with the condition variable. andre@0: ** andre@0: ** Condition variables are synchronization objects that threads can use andre@0: ** to wait for some condition to occur. andre@0: ** andre@0: ** This may fail if memory is tight or if some operating system resource andre@0: ** is low. andre@0: */ andre@0: PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) andre@0: { andre@0: PRCondVar *cvar; andre@0: andre@0: cvar = PR_NEWZAP(PRCondVar); andre@0: if (cvar) { andre@0: if (_PR_InitCondVar(cvar, lock) != PR_SUCCESS) { andre@0: PR_DELETE(cvar); andre@0: return NULL; andre@0: } andre@0: } else { andre@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); andre@0: } andre@0: return cvar; andre@0: } andre@0: andre@0: PRStatus _PR_InitCondVar(PRCondVar *cvar, PRLock *lock) andre@0: { andre@0: PR_ASSERT(lock != NULL); andre@0: andre@0: #ifdef _PR_GLOBAL_THREADS_ONLY andre@0: if(_PR_MD_NEW_CV(&cvar->md)) { andre@0: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: #endif andre@0: if (_PR_MD_NEW_LOCK(&(cvar->ilock)) != PR_SUCCESS) { andre@0: PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: cvar->lock = lock; andre@0: PR_INIT_CLIST(&cvar->condQ); andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: /* andre@0: ** Destroy a condition variable. There must be no thread andre@0: ** waiting on the condvar. The caller is responsible for guaranteeing andre@0: ** that the condvar is no longer in use. andre@0: ** andre@0: */ andre@0: PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar) andre@0: { andre@0: _PR_FreeCondVar(cvar); andre@0: PR_DELETE(cvar); andre@0: } andre@0: andre@0: void _PR_FreeCondVar(PRCondVar *cvar) andre@0: { andre@0: PR_ASSERT(cvar->condQ.next == &cvar->condQ); andre@0: andre@0: #ifdef _PR_GLOBAL_THREADS_ONLY andre@0: _PR_MD_FREE_CV(&cvar->md); andre@0: #endif andre@0: _PR_MD_FREE_LOCK(&(cvar->ilock)); andre@0: } andre@0: andre@0: /* andre@0: ** Wait for a notify on the condition variable. Sleep for "tiemout" amount andre@0: ** of ticks (if "timeout" is zero then the sleep is indefinite). While andre@0: ** the thread is waiting it unlocks lock. When the wait has andre@0: ** finished the thread regains control of the condition variable after andre@0: ** locking the associated lock. andre@0: ** andre@0: ** The thread waiting on the condvar will be resumed when the condvar is andre@0: ** notified (assuming the thread is the next in line to receive the andre@0: ** notify) or when the timeout elapses. andre@0: ** andre@0: ** Returns PR_FAILURE if the caller has not locked the lock associated andre@0: ** with the condition variable or the thread has been interrupted. andre@0: */ andre@0: extern PRThread *suspendAllThread; andre@0: PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout) andre@0: { andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: andre@0: PR_ASSERT(cvar->lock->owner == me); andre@0: PR_ASSERT(me != suspendAllThread); andre@0: if (cvar->lock->owner != me) return PR_FAILURE; andre@0: andre@0: return _PR_WaitCondVar(me, cvar, cvar->lock, timeout); andre@0: } andre@0: andre@0: /* andre@0: ** Notify the highest priority thread waiting on the condition andre@0: ** variable. If a thread is waiting on the condition variable (using andre@0: ** PR_Wait) then it is awakened and begins waiting on the lock. andre@0: */ andre@0: PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar) andre@0: { andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: andre@0: PR_ASSERT(cvar->lock->owner == me); andre@0: PR_ASSERT(me != suspendAllThread); andre@0: if (cvar->lock->owner != me) return PR_FAILURE; andre@0: andre@0: _PR_NotifyCondVar(cvar, me); andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: /* andre@0: ** Notify all of the threads waiting on the condition variable. All of andre@0: ** threads are notified in turn. The highest priority thread will andre@0: ** probably acquire the lock. andre@0: */ andre@0: PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) andre@0: { andre@0: PRCList *q; andre@0: PRIntn is; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: andre@0: PR_ASSERT(cvar->lock->owner == me); andre@0: if (cvar->lock->owner != me) return PR_FAILURE; andre@0: andre@0: #ifdef _PR_GLOBAL_THREADS_ONLY andre@0: _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock); andre@0: return PR_SUCCESS; andre@0: #else /* _PR_GLOBAL_THREADS_ONLY */ andre@0: if ( !_PR_IS_NATIVE_THREAD(me)) andre@0: _PR_INTSOFF(is); andre@0: _PR_CVAR_LOCK(cvar); andre@0: q = cvar->condQ.next; andre@0: while (q != &cvar->condQ) { andre@0: PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); andre@0: _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); andre@0: q = q->next; andre@0: } andre@0: _PR_CVAR_UNLOCK(cvar); andre@0: if (!_PR_IS_NATIVE_THREAD(me)) andre@0: _PR_INTSON(is); andre@0: andre@0: return PR_SUCCESS; andre@0: #endif /* _PR_GLOBAL_THREADS_ONLY */ andre@0: } andre@0: andre@0: andre@0: /*********************************************************************/ andre@0: /*********************************************************************/ andre@0: /********************ROUTINES FOR DCE EMULATION***********************/ andre@0: /*********************************************************************/ andre@0: /*********************************************************************/ andre@0: #include "prpdce.h" andre@0: andre@0: PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) andre@0: { andre@0: PRCondVar *cvar = PR_NEWZAP(PRCondVar); andre@0: if (NULL != cvar) andre@0: { andre@0: if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) andre@0: { andre@0: PR_DELETE(cvar); cvar = NULL; andre@0: } andre@0: else andre@0: { andre@0: PR_INIT_CLIST(&cvar->condQ); andre@0: cvar->lock = _PR_NAKED_CV_LOCK; andre@0: } andre@0: andre@0: } andre@0: return cvar; andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar) andre@0: { andre@0: PR_ASSERT(cvar->condQ.next == &cvar->condQ); andre@0: PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); andre@0: andre@0: _PR_MD_FREE_LOCK(&(cvar->ilock)); andre@0: andre@0: PR_DELETE(cvar); andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PRP_NakedWait( andre@0: PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) andre@0: { andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); andre@0: return _PR_WaitCondVar(me, cvar, lock, timeout); andre@0: } /* PRP_NakedWait */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar) andre@0: { andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); andre@0: andre@0: _PR_NotifyCondVar(cvar, me); andre@0: andre@0: return PR_SUCCESS; andre@0: } /* PRP_NakedNotify */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) andre@0: { andre@0: PRCList *q; andre@0: PRIntn is; andre@0: PRThread *me = _PR_MD_CURRENT_THREAD(); andre@0: PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); andre@0: andre@0: if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); andre@0: _PR_MD_LOCK( &(cvar->ilock) ); andre@0: q = cvar->condQ.next; andre@0: while (q != &cvar->condQ) { andre@0: PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); andre@0: _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); andre@0: q = q->next; andre@0: } andre@0: _PR_MD_UNLOCK( &(cvar->ilock) ); andre@0: if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); andre@0: andre@0: return PR_SUCCESS; andre@0: } /* PRP_NakedBroadcast */ andre@0: