/* ** Notify all of the threads waiting on the condition variable. All of ** threads are notified in turn. The highest priority thread will ** probably acquire the lock. */ PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) { PRCList *q; PRIntn is; PRThread *me = _PR_MD_CURRENT_THREAD(); PR_ASSERT(cvar->lock->owner == me); if (cvar->lock->owner != me) return PR_FAILURE; #ifdef _PR_GLOBAL_THREADS_ONLY _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock); return PR_SUCCESS; #else /* _PR_GLOBAL_THREADS_ONLY */ if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); _PR_CVAR_LOCK(cvar); q = cvar->condQ.next; while (q != &cvar->condQ) { PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); q = q->next; } _PR_CVAR_UNLOCK(cvar); if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); return PR_SUCCESS; #endif /* _PR_GLOBAL_THREADS_ONLY */ }
void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me) { #ifdef _PR_GLOBAL_THREADS_ONLY _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock); #else /* _PR_GLOBAL_THREADS_ONLY */ PRCList *q; PRIntn is; if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); _PR_CVAR_LOCK(cvar); q = cvar->condQ.next; while (q != &cvar->condQ) { #ifndef XP_MAC PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar)); #endif if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar) { if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE) break; } q = q->next; } _PR_CVAR_UNLOCK(cvar); if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); #endif /* _PR_GLOBAL_THREADS_ONLY */ }
/* ** Test and then lock the lock if it's not already locked by some other ** thread. Return PR_FALSE if some other thread owned the lock at the ** time of the call. */ PR_IMPLEMENT(PRBool) PR_TestAndLock(PRLock *lock) { PRThread *me = _PR_MD_CURRENT_THREAD(); PRBool rv = PR_FALSE; PRIntn is; #ifdef _PR_GLOBAL_THREADS_ONLY is = _PR_MD_TEST_AND_LOCK(&lock->ilock); if (is == 0) { lock->owner = me; return PR_TRUE; } return PR_FALSE; #else /* _PR_GLOBAL_THREADS_ONLY */ #ifndef _PR_LOCAL_THREADS_ONLY if (_native_threads_only) { is = _PR_MD_TEST_AND_LOCK(&lock->ilock); if (is == 0) { lock->owner = me; return PR_TRUE; } return PR_FALSE; } #endif if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); _PR_LOCK_LOCK(lock); if (lock->owner == 0) { /* Just got the lock */ lock->owner = me; lock->priority = me->priority; /* Add the granted lock to this owning thread's lock list */ PR_APPEND_LINK(&lock->links, &me->lockList); rv = PR_TRUE; } _PR_LOCK_UNLOCK(lock); if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); return rv; #endif /* _PR_GLOBAL_THREADS_ONLY */ }
PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) { PRCList *q; PRIntn is; PRThread *me = _PR_MD_CURRENT_THREAD(); PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); _PR_MD_LOCK( &(cvar->ilock) ); q = cvar->condQ.next; while (q != &cvar->condQ) { PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); q = q->next; } _PR_MD_UNLOCK( &(cvar->ilock) ); if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); return PR_SUCCESS; } /* PRP_NakedBroadcast */
/* ** Unlock the lock. */ PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) { PRCList *q; PRThreadPriority pri, boost; PRIntn is; PRThread *me = _PR_MD_CURRENT_THREAD(); PR_ASSERT(lock != NULL); PR_ASSERT(lock->owner == me); PR_ASSERT(me != suspendAllThread); PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); if (lock->owner != me) { return PR_FAILURE; } #ifdef _PR_GLOBAL_THREADS_ONLY lock->owner = 0; _PR_MD_UNLOCK(&lock->ilock); return PR_SUCCESS; #else /* _PR_GLOBAL_THREADS_ONLY */ if (_native_threads_only) { lock->owner = 0; _PR_MD_UNLOCK(&lock->ilock); return PR_SUCCESS; } if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); _PR_LOCK_LOCK(lock); /* Remove the lock from the owning thread's lock list */ PR_REMOVE_LINK(&lock->links); pri = lock->priority; boost = lock->boostPriority; if (boost > pri) { /* ** We received a priority boost during the time we held the lock. ** We need to figure out what priority to move to by scanning ** down our list of lock's that we are still holding and using ** the highest boosted priority found. */ q = me->lockList.next; while (q != &me->lockList) { PRLock *ll = _PR_LOCK_PTR(q); if (ll->boostPriority > pri) { pri = ll->boostPriority; } q = q->next; } if (pri != me->priority) { _PR_SetThreadPriority(me, pri); } } /* Unblock the first waiting thread */ q = lock->waitQ.next; if (q != &lock->waitQ) _PR_UnblockLockWaiter(lock); lock->boostPriority = PR_PRIORITY_LOW; lock->owner = 0; _PR_LOCK_UNLOCK(lock); if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); return PR_SUCCESS; #endif /* _PR_GLOBAL_THREADS_ONLY */ }
/* ** Make the given thread wait for the given condition variable */ PRStatus _PR_WaitCondVar( PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) { PRIntn is; PRStatus rv = PR_SUCCESS; PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); #ifdef _PR_GLOBAL_THREADS_ONLY if (_PR_PENDING_INTERRUPT(thread)) { PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); thread->flags &= ~_PR_INTERRUPT; return PR_FAILURE; } thread->wait.cvar = cvar; lock->owner = NULL; _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout); thread->wait.cvar = NULL; lock->owner = thread; if (_PR_PENDING_INTERRUPT(thread)) { PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); thread->flags &= ~_PR_INTERRUPT; return PR_FAILURE; } return PR_SUCCESS; #else /* _PR_GLOBAL_THREADS_ONLY */ if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_INTSOFF(is); _PR_CVAR_LOCK(cvar); _PR_THREAD_LOCK(thread); if (_PR_PENDING_INTERRUPT(thread)) { PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); thread->flags &= ~_PR_INTERRUPT; _PR_CVAR_UNLOCK(cvar); _PR_THREAD_UNLOCK(thread); if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_INTSON(is); return PR_FAILURE; } thread->state = _PR_COND_WAIT; thread->wait.cvar = cvar; /* ** Put the caller thread on the condition variable's wait Q */ PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ); /* Note- for global scope threads, we don't put them on the * global sleepQ, so each global thread must put itself * to sleep only for the time it wants to. */ if ( !_PR_IS_NATIVE_THREAD(thread) ) { _PR_SLEEPQ_LOCK(thread->cpu); _PR_ADD_SLEEPQ(thread, timeout); _PR_SLEEPQ_UNLOCK(thread->cpu); } _PR_CVAR_UNLOCK(cvar); _PR_THREAD_UNLOCK(thread); /* ** Release lock protecting the condition variable and thereby giving time ** to the next thread which can potentially notify on the condition variable */ PR_Unlock(lock); PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_Wait: cvar=%p waiting for %d", cvar, timeout)); rv = _PR_MD_WAIT(thread, timeout); _PR_CVAR_LOCK(cvar); PR_REMOVE_LINK(&thread->waitQLinks); _PR_CVAR_UNLOCK(cvar); PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_Wait: cvar=%p done waiting", cvar)); if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_INTSON(is); /* Acquire lock again that we had just relinquished */ PR_Lock(lock); if (_PR_PENDING_INTERRUPT(thread)) { PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); thread->flags &= ~_PR_INTERRUPT; return PR_FAILURE; } return rv; #endif /* _PR_GLOBAL_THREADS_ONLY */ }