/*
 * 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);
}
Beispiel #2
0
/*
 * 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;
	}
}
Beispiel #3
0
/*
 * Take thread off its wait queue and make it runnable.
 * Returns with thread lock held.
 */
void
waitq_setrun(kthread_t *t)
{
	waitq_t *wq = t->t_waitq;

	ASSERT(THREAD_LOCK_HELD(t));

	ASSERT(ISWAITING(t));
	if (wq == NULL)
		panic("waitq_setrun: thread %p is not on waitq", t);
	waitq_dequeue(wq, t);
	CL_SETRUN(t);
}
Beispiel #4
0
/*
 * 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);
}
Beispiel #5
0
/*
 * Unsleep a thread that's blocked on a condition variable.
 */
static void
cv_unsleep(kthread_t *t)
{
	condvar_impl_t *cvp = (condvar_impl_t *)t->t_wchan;
	sleepq_head_t *sqh = SQHASH(cvp);

	ASSERT(THREAD_LOCK_HELD(t));

	if (cvp == NULL)
		panic("cv_unsleep: thread %p not on sleepq %p", t, sqh);
	DTRACE_SCHED1(wakeup, kthread_t *, t);
	sleepq_unsleep(t);
	if (cvp->cv_waiters != CV_MAX_WAITERS)
		cvp->cv_waiters--;
	disp_lock_exit_high(&sqh->sq_lock);
	CL_SETRUN(t);
}
Beispiel #6
0
/*
 * Take the first thread off the wait queue and make it runnable.
 * Return the pointer to the thread or NULL if waitq is empty
 */
static kthread_t *
waitq_runfirst(waitq_t *wq)
{
	kthread_t *t;

	t = waitq_takeone(wq);
	if (t != NULL) {
		/*
		 * t should have transition lock held.
		 * CL_SETRUN() will replace it with dispq lock and keep it held.
		 * thread_unlock() will drop dispq lock and restore PIL.
		 */
		ASSERT(THREAD_LOCK_HELD(t));
		CL_SETRUN(t);
		thread_unlock(t);
	}
	return (t);
}