/* * 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); } }
void cv_signal(kcondvar_t *cvp) { condvar_impl_t *cp = (condvar_impl_t *)cvp; /* make sure the cv_waiters field looks sane */ ASSERT(cp->cv_waiters <= CV_MAX_WAITERS); if (cp->cv_waiters > 0) { sleepq_head_t *sqh = SQHASH(cp); disp_lock_enter(&sqh->sq_lock); ASSERT(CPU_ON_INTR(CPU) == 0); if (cp->cv_waiters & CV_WAITERS_MASK) { kthread_t *t; cp->cv_waiters--; t = sleepq_wakeone_chan(&sqh->sq_queue, cp); /* * If cv_waiters is non-zero (and less than * CV_MAX_WAITERS) there should be a thread * in the queue. */ ASSERT(t != NULL); } else if (sleepq_wakeone_chan(&sqh->sq_queue, cp) == NULL) { cp->cv_waiters = 0; } disp_lock_exit(&sqh->sq_lock); } }
/* * Change the priority of a thread that's blocked on a condition variable. */ static void cv_change_pri(kthread_t *t, pri_t pri, pri_t *t_prip) { condvar_impl_t *cvp = (condvar_impl_t *)t->t_wchan; sleepq_t *sqp = t->t_sleepq; ASSERT(THREAD_LOCK_HELD(t)); ASSERT(&SQHASH(cvp)->sq_queue == sqp); if (cvp == NULL) panic("cv_change_pri: %p not on sleep queue", t); sleepq_dequeue(t); *t_prip = pri; sleepq_insert(sqp, t); }
void cv_broadcast(kcondvar_t *cvp) { condvar_impl_t *cp = (condvar_impl_t *)cvp; /* make sure the cv_waiters field looks sane */ ASSERT(cp->cv_waiters <= CV_MAX_WAITERS); if (cp->cv_waiters > 0) { sleepq_head_t *sqh = SQHASH(cp); disp_lock_enter(&sqh->sq_lock); ASSERT(CPU_ON_INTR(CPU) == 0); sleepq_wakeall_chan(&sqh->sq_queue, cp); cp->cv_waiters = 0; disp_lock_exit(&sqh->sq_lock); } }
/* * 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); }
/* * try to acquire the semaphore. if the semaphore is greater than * zero, then the semaphore is granted and returns 1. otherwise * return 0. */ int sema_tryp(ksema_t *sp) { sema_impl_t *s; sleepq_head_t *sqh; int gotit = 0; s = (sema_impl_t *)sp; sqh = SQHASH(s); disp_lock_enter(&sqh->sq_lock); if (s->s_count > 0) { s->s_count--; gotit = 1; } disp_lock_exit(&sqh->sq_lock); return (gotit); }
/* * The cv_block() function blocks a thread on a condition variable * by putting it in a hashed sleep queue associated with the * synchronization object. * * Threads are taken off the hashed sleep queues via calls to * cv_signal(), cv_broadcast(), or cv_unsleep(). */ static void cv_block(condvar_impl_t *cvp) { kthread_t *t = curthread; klwp_t *lwp = ttolwp(t); sleepq_head_t *sqh; ASSERT(THREAD_LOCK_HELD(t)); ASSERT(t != CPU->cpu_idle_thread); ASSERT(CPU_ON_INTR(CPU) == 0); ASSERT(t->t_wchan0 == NULL && t->t_wchan == NULL); ASSERT(t->t_state == TS_ONPROC); t->t_schedflag &= ~TS_SIGNALLED; CL_SLEEP(t); /* assign kernel priority */ t->t_wchan = (caddr_t)cvp; t->t_sobj_ops = &cv_sobj_ops; DTRACE_SCHED(sleep); /* * The check for t_intr is to avoid doing the * account for an interrupt thread on the still-pinned * lwp's statistics. */ if (lwp != NULL && t->t_intr == NULL) { lwp->lwp_ru.nvcsw++; (void) new_mstate(t, LMS_SLEEP); } sqh = SQHASH(cvp); disp_lock_enter_high(&sqh->sq_lock); if (cvp->cv_waiters < CV_MAX_WAITERS) cvp->cv_waiters++; ASSERT(cvp->cv_waiters <= CV_MAX_WAITERS); THREAD_SLEEP(t, &sqh->sq_lock); sleepq_insert(&sqh->sq_queue, t); /* * THREAD_SLEEP() moves curthread->t_lockp to point to the * lock sqh->sq_lock. This lock is later released by the caller * when it calls thread_unlock() on curthread. */ }
/* * the semaphore is granted when the semaphore's * count is greater than zero and blocks when equal * to zero. */ void sema_p(ksema_t *sp) { sema_impl_t *s; disp_lock_t *sqlp; s = (sema_impl_t *)sp; sqlp = &SQHASH(s)->sq_lock; disp_lock_enter(sqlp); ASSERT(s->s_count >= 0); while (s->s_count == 0) { if (panicstr) { disp_lock_exit(sqlp); return; } thread_lock_high(curthread); SEMA_BLOCK(s, sqlp); thread_unlock_nopreempt(curthread); swtch(); disp_lock_enter(sqlp); } s->s_count--; disp_lock_exit(sqlp); }
/* * 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); }