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