/* * the semaphore's count is incremented by one. a blocked thread * is awakened and re-tries to acquire the semaphore. */ void sema_v(ksema_t *sp) { sema_impl_t *s; kthread_t *sq, *tp; disp_lock_t *sqlp; s = (sema_impl_t *)sp; sqlp = &SQHASH(s)->sq_lock; disp_lock_enter(sqlp); if (panicstr) { disp_lock_exit(sqlp); return; } s->s_count++; sq = s->s_slpq; if (sq != NULL) { tp = sq; ASSERT(THREAD_LOCK_HELD(tp)); sq = sq->t_link; tp->t_link = NULL; DTRACE_SCHED1(wakeup, kthread_t *, tp); tp->t_sobj_ops = NULL; tp->t_wchan = NULL; ASSERT(tp->t_state == TS_SLEEP); CL_WAKEUP(tp); s->s_slpq = sq; disp_lock_exit_high(sqlp); thread_unlock(tp); } else { disp_lock_exit(sqlp); } }
/* * Wake threads that are blocked in a turnstile. */ void turnstile_wakeup(turnstile_t *ts, int qnum, int nthreads, kthread_t *owner) { turnstile_chain_t *tc = &TURNSTILE_CHAIN(ts->ts_sobj); sleepq_t *sqp = &ts->ts_sleepq[qnum]; ASSERT(DISP_LOCK_HELD(&tc->tc_lock)); /* * Waive any priority we may have inherited from this turnstile. */ if (ts->ts_inheritor != NULL) { turnstile_pi_waive(ts); } while (nthreads-- > 0) { kthread_t *t = sqp->sq_first; ASSERT(t->t_ts == ts); ASSERT(ts->ts_waiters > 1 || ts->ts_inheritor == NULL); DTRACE_SCHED1(wakeup, kthread_t *, t); turnstile_dequeue(t); CL_WAKEUP(t); /* previous thread lock, tc_lock, not dropped */ /* * If the caller did direct handoff of ownership, * make the new owner inherit from this turnstile. */ if (t == owner) { kthread_t *wp = ts->ts_sleepq[TS_WRITER_Q].sq_first; kthread_t *rp = ts->ts_sleepq[TS_READER_Q].sq_first; pri_t wpri = wp ? DISP_PRIO(wp) : 0; pri_t rpri = rp ? DISP_PRIO(rp) : 0; turnstile_pi_inherit(ts, t, MAX(wpri, rpri)); owner = NULL; } thread_unlock_high(t); /* drop run queue lock */ } if (owner != NULL) panic("turnstile_wakeup: owner %p not woken", (void *)owner); disp_lock_exit(&tc->tc_lock); }
/* * similiar to sema_p except that it blocks at an interruptible * priority. if a signal is present then return 1 otherwise 0. */ int sema_p_sig(ksema_t *sp) { kthread_t *t = curthread; klwp_t *lwp = ttolwp(t); sema_impl_t *s; disp_lock_t *sqlp; if (lwp == NULL) { sema_p(sp); return (0); } s = (sema_impl_t *)sp; sqlp = &SQHASH(s)->sq_lock; disp_lock_enter(sqlp); ASSERT(s->s_count >= 0); while (s->s_count == 0) { proc_t *p = ttoproc(t); thread_lock_high(t); t->t_flag |= T_WAKEABLE; SEMA_BLOCK(s, sqlp); lwp->lwp_asleep = 1; lwp->lwp_sysabort = 0; thread_unlock_nopreempt(t); if (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t)) setrun(t); swtch(); t->t_flag &= ~T_WAKEABLE; if (ISSIG(t, FORREAL) || lwp->lwp_sysabort || MUSTRETURN(p, t)) { kthread_t *sq, *tp; lwp->lwp_asleep = 0; lwp->lwp_sysabort = 0; disp_lock_enter(sqlp); sq = s->s_slpq; /* * in case sema_v and interrupt happen * at the same time, we need to pass the * sema_v to the next thread. */ if ((sq != NULL) && (s->s_count > 0)) { tp = sq; ASSERT(THREAD_LOCK_HELD(tp)); sq = sq->t_link; tp->t_link = NULL; DTRACE_SCHED1(wakeup, kthread_t *, tp); tp->t_sobj_ops = NULL; tp->t_wchan = NULL; ASSERT(tp->t_state == TS_SLEEP); CL_WAKEUP(tp); s->s_slpq = sq; disp_lock_exit_high(sqlp); thread_unlock(tp); } else { disp_lock_exit(sqlp); } return (1); } lwp->lwp_asleep = 0; disp_lock_enter(sqlp); } s->s_count--; disp_lock_exit(sqlp); return (0); }