/* * Notify thread waiting on cvar; called when thread is interrupted * The thread lock is held on entry and released before return */ void _PR_NotifyLockedThread (PRThread *thread) { PRThread *me = _PR_MD_CURRENT_THREAD(); PRCondVar *cvar; PRThreadPriority pri; if ( !_PR_IS_NATIVE_THREAD(me)) PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); cvar = thread->wait.cvar; thread->wait.cvar = NULL; _PR_THREAD_UNLOCK(thread); _PR_CVAR_LOCK(cvar); _PR_THREAD_LOCK(thread); if (!_PR_IS_NATIVE_THREAD(thread)) { _PR_SLEEPQ_LOCK(thread->cpu); /* The notify and timeout can collide; in which case both may * attempt to delete from the sleepQ; only let one do it. */ if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) _PR_DEL_SLEEPQ(thread, PR_TRUE); _PR_SLEEPQ_UNLOCK(thread->cpu); /* Make thread runnable */ pri = thread->priority; thread->state = _PR_RUNNABLE; PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); _PR_AddThreadToRunQ(me, thread); _PR_THREAD_UNLOCK(thread); _PR_MD_WAKEUP_WAITER(thread); } else { if (thread->flags & _PR_SUSPENDING) { /* * set thread state to SUSPENDED; a Resume operation * on the thread will enable the thread to run */ thread->state = _PR_SUSPENDED; } else thread->state = _PR_RUNNING; _PR_THREAD_UNLOCK(thread); _PR_MD_WAKEUP_WAITER(thread); } _PR_CVAR_UNLOCK(cvar); return; }
/* ** Unblock the first runnable waiting thread. Skip over ** threads that are trying to be suspended ** Note: Caller must hold _PR_LOCK_LOCK() */ void _PR_UnblockLockWaiter(PRLock *lock) { PRThread *t = NULL; PRThread *me; PRCList *q; q = lock->waitQ.next; PR_ASSERT(q != &lock->waitQ); while (q != &lock->waitQ) { /* Unblock first waiter */ t = _PR_THREAD_CONDQ_PTR(q); /* ** We are about to change the thread's state to runnable and for local ** threads, we are going to assign a cpu to it. So, protect thread's ** data structure. */ _PR_THREAD_LOCK(t); if (t->flags & _PR_SUSPENDING) { q = q->next; _PR_THREAD_UNLOCK(t); continue; } /* Found a runnable thread */ PR_ASSERT(t->state == _PR_LOCK_WAIT); PR_ASSERT(t->wait.lock == lock); t->wait.lock = 0; PR_REMOVE_LINK(&t->waitQLinks); /* take it off lock's waitQ */ /* ** If this is a native thread, nothing else to do except to wake it ** up by calling the machine dependent wakeup routine. ** ** If this is a local thread, we need to assign it a cpu and ** put the thread on that cpu's run queue. There are two cases to ** take care of. If the currently running thread is also a local ** thread, we just assign our own cpu to that thread and put it on ** the cpu's run queue. If the the currently running thread is a ** native thread, we assign the primordial cpu to it (on NT, ** MD_WAKEUP handles the cpu assignment). */ if ( !_PR_IS_NATIVE_THREAD(t) ) { t->state = _PR_RUNNABLE; me = _PR_MD_CURRENT_THREAD(); _PR_AddThreadToRunQ(me, t); _PR_THREAD_UNLOCK(t); } else { t->state = _PR_RUNNING; _PR_THREAD_UNLOCK(t); } _PR_MD_WAKEUP_WAITER(t); break; } return; }
/* ** Notify one thread that it has finished waiting on a condition variable ** Caller must hold the _PR_CVAR_LOCK(cv) */ PRBool _PR_NotifyThread (PRThread *thread, PRThread *me) { PRBool rv; PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); _PR_THREAD_LOCK(thread); PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); if ( !_PR_IS_NATIVE_THREAD(thread) ) { if (thread->wait.cvar != NULL) { thread->wait.cvar = NULL; _PR_SLEEPQ_LOCK(thread->cpu); /* The notify and timeout can collide; in which case both may * attempt to delete from the sleepQ; only let one do it. */ if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) _PR_DEL_SLEEPQ(thread, PR_TRUE); _PR_SLEEPQ_UNLOCK(thread->cpu); if (thread->flags & _PR_SUSPENDING) { /* * set thread state to SUSPENDED; a Resume operation * on the thread will move it to the runQ */ thread->state = _PR_SUSPENDED; _PR_MISCQ_LOCK(thread->cpu); _PR_ADD_SUSPENDQ(thread, thread->cpu); _PR_MISCQ_UNLOCK(thread->cpu); _PR_THREAD_UNLOCK(thread); } else { /* Make thread runnable */ thread->state = _PR_RUNNABLE; _PR_THREAD_UNLOCK(thread); _PR_AddThreadToRunQ(me, thread); _PR_MD_WAKEUP_WAITER(thread); } rv = PR_TRUE; } else { /* Thread has already been notified */ _PR_THREAD_UNLOCK(thread); rv = PR_FALSE; } } else { /* If the thread is a native thread */ if (thread->wait.cvar) { thread->wait.cvar = NULL; if (thread->flags & _PR_SUSPENDING) { /* * set thread state to SUSPENDED; a Resume operation * on the thread will enable the thread to run */ thread->state = _PR_SUSPENDED; } else thread->state = _PR_RUNNING; _PR_THREAD_UNLOCK(thread); _PR_MD_WAKEUP_WAITER(thread); rv = PR_TRUE; } else { _PR_THREAD_UNLOCK(thread); rv = PR_FALSE; } } return rv; }