/* * Wake up a thread blocked in a turnstile. Used to enable interruptibility * of threads blocked on a SOBJ_USER_PI sobj. * * The implications of this interface are: * * 1. turnstile_block() may return with an EINTR. * 2. When the owner of an sobj releases it, but no turnstile is found (i.e. * no waiters), the (prior) owner must call turnstile_pi_recalc() to * waive any priority inherited from interrupted waiters. * * When a waiter is interrupted, disinheriting its willed priority from the * inheritor would require holding the inheritor's thread lock, while also * holding the waiter's thread lock which is a turnstile lock. If the * inheritor's thread lock is not free, and is also a turnstile lock that * is out of lock order, the waiter's thread lock would have to be dropped. * This leads to complications for the caller of turnstile_unsleep(), since * the caller holds the waiter's thread lock. So, instead of disinheriting * on waiter interruption, the owner is required to follow rule 2 above. * * Avoiding disinherit on waiter interruption seems acceptable because * the owner runs at an unnecessarily high priority only while sobj is held, * which it would have done in any case, if the waiter had not been interrupted. */ void turnstile_unsleep(kthread_t *t) { turnstile_dequeue(t); THREAD_TRANSITION(t); CL_SETRUN(t); }
/* * Wakeup a thread sleeping on a semaphore, and put it * on the dispatch queue. * Called via SOBJ_UNSLEEP(). */ static void sema_unsleep(kthread_t *t) { kthread_t **tpp; kthread_t *tp; sema_impl_t *s; ASSERT(THREAD_LOCK_HELD(t)); s = (sema_impl_t *)t->t_wchan; tpp = &s->s_slpq; while ((tp = *tpp) != NULL) { if (tp == t) { *tpp = t->t_link; t->t_link = NULL; t->t_sobj_ops = NULL; t->t_wchan = NULL; t->t_wchan0 = NULL; /* * Change thread to transition state and * drop the semaphore sleep queue lock. */ THREAD_TRANSITION(t); CL_SETRUN(t); return; } tpp = &tp->t_link; } }
/* * Place the thread in question on the run q. */ static void shuttle_unsleep(kthread_t *t) { ASSERT(THREAD_LOCK_HELD(t)); /* Waiting on a shuttle */ ASSERT(t->t_wchan0 == (caddr_t)1 && t->t_wchan == NULL); t->t_flag &= ~T_WAKEABLE; t->t_wchan0 = NULL; t->t_sobj_ops = NULL; THREAD_TRANSITION(t); CL_SETRUN(t); }
static void waitq_dequeue(waitq_t *wq, kthread_t *t) { ASSERT(THREAD_LOCK_HELD(t)); ASSERT(t->t_waitq == wq); ASSERT(ISWAITING(t)); waitq_unlink(wq, t); DTRACE_SCHED1(cpucaps__wakeup, kthread_t *, t); /* * Change thread to transition state and drop the wait queue lock. The * thread will remain locked since its t_lockp points to the * transition_lock. */ THREAD_TRANSITION(t); }