diff options
Diffstat (limited to 'sys/kern/subr_sleepqueue.c')
-rw-r--r-- | sys/kern/subr_sleepqueue.c | 157 |
1 files changed, 76 insertions, 81 deletions
diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index 238d4bf..464cf28 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -318,8 +318,10 @@ sleepq_add(void *wchan, struct mtx *lock, const char *wmesg, int flags) mtx_lock_spin(&sched_lock); td->td_wchan = wchan; td->td_wmesg = wmesg; - if (flags & SLEEPQ_INTERRUPTIBLE) + if (flags & SLEEPQ_INTERRUPTIBLE) { td->td_flags |= TDF_SINTR; + td->td_flags &= ~TDF_SLEEPABORT; + } mtx_unlock_spin(&sched_lock); } @@ -345,55 +347,64 @@ sleepq_set_timeout(void *wchan, int timo) /* * Marks the pending sleep of the current thread as interruptible and * makes an initial check for pending signals before putting a thread - * to sleep. + * to sleep. Return with sleep queue and scheduler lock held. */ -int +static int sleepq_catch_signals(void *wchan) { struct sleepqueue_chain *sc; struct sleepqueue *sq; struct thread *td; struct proc *p; - int sig; + struct sigacts *ps; + int sig, ret; td = curthread; - p = td->td_proc; + p = curproc; sc = SC_LOOKUP(wchan); mtx_assert(&sc->sc_lock, MA_OWNED); - MPASS(td->td_sleepqueue == NULL); MPASS(wchan != NULL); CTR3(KTR_PROC, "sleepq catching signals: thread %p (pid %ld, %s)", - (void *)td, (long)p->p_pid, p->p_comm); + (void *)td, (long)p->p_pid, p->p_comm); - /* Mark thread as being in an interruptible sleep. */ MPASS(td->td_flags & TDF_SINTR); - MPASS(TD_ON_SLEEPQ(td)); - sleepq_release(wchan); + mtx_unlock_spin(&sc->sc_lock); /* See if there are any pending signals for this thread. */ PROC_LOCK(p); - mtx_lock(&p->p_sigacts->ps_mtx); + ps = p->p_sigacts; + mtx_lock(&ps->ps_mtx); sig = cursig(td); - mtx_unlock(&p->p_sigacts->ps_mtx); - if (sig == 0 && thread_suspend_check(1)) - sig = SIGSTOP; - PROC_UNLOCK(p); + if (sig == 0) { + mtx_unlock(&ps->ps_mtx); + ret = thread_suspend_check(1); + MPASS(ret == 0 || ret == EINTR || ret == ERESTART); + } else { + if (SIGISMEMBER(ps->ps_sigintr, sig)) + ret = EINTR; + else + ret = ERESTART; + mtx_unlock(&ps->ps_mtx); + } - /* - * If there were pending signals and this thread is still on - * the sleep queue, remove it from the sleep queue. If the - * thread was removed from the sleep queue while we were blocked - * above, then clear TDF_SINTR before returning. - */ - sleepq_lock(wchan); - sq = sleepq_lookup(wchan); - mtx_lock_spin(&sched_lock); - if (TD_ON_SLEEPQ(td) && sig != 0) - sleepq_resume_thread(sq, td, -1); - else if (!TD_ON_SLEEPQ(td) && sig == 0) + if (ret) { + PROC_UNLOCK(p); + /* + * If there were pending signals and this thread is still on + * the sleep queue, remove it from the sleep queue. + */ + mtx_lock_spin(&sc->sc_lock); + sq = sleepq_lookup(wchan); + mtx_lock_spin(&sched_lock); + if (TD_ON_SLEEPQ(td)) + sleepq_resume_thread(sq, td, -1); td->td_flags &= ~TDF_SINTR; - mtx_unlock_spin(&sched_lock); - return (sig); + } else { + mtx_lock_spin(&sc->sc_lock); + mtx_lock_spin(&sched_lock); + PROC_UNLOCK(p); + } + return (ret); } /* @@ -409,6 +420,7 @@ sleepq_switch(void *wchan) td = curthread; sc = SC_LOOKUP(wchan); mtx_assert(&sc->sc_lock, MA_OWNED); + mtx_assert(&sched_lock, MA_OWNED); /* * If we have a sleep queue, then we've already been woken up, so @@ -417,16 +429,13 @@ sleepq_switch(void *wchan) if (td->td_sleepqueue != NULL) { MPASS(!TD_ON_SLEEPQ(td)); mtx_unlock_spin(&sc->sc_lock); - mtx_lock_spin(&sched_lock); return; } /* * Otherwise, actually go to sleep. */ - mtx_lock_spin(&sched_lock); mtx_unlock_spin(&sc->sc_lock); - sched_sleep(td); TD_SET_SLEEPING(td); mi_switch(SW_VOL, NULL); @@ -485,52 +494,19 @@ sleepq_check_signals(void) mtx_assert(&sched_lock, MA_OWNED); td = curthread; - /* - * If TDF_SINTR is clear, then we were awakened while executing - * sleepq_catch_signals(). - */ - if (!(td->td_flags & TDF_SINTR)) - return (0); - /* We are no longer in an interruptible sleep. */ - td->td_flags &= ~TDF_SINTR; + if (td->td_flags & TDF_SINTR) + td->td_flags &= ~TDF_SINTR; - if (td->td_flags & TDF_INTERRUPT) + if (td->td_flags & TDF_SLEEPABORT) { + td->td_flags &= ~TDF_SLEEPABORT; return (td->td_intrval); - return (0); -} + } -/* - * If we were in an interruptible sleep and we weren't interrupted and - * didn't timeout, check to see if there are any pending signals and - * which return value we should use if so. The return value from an - * earlier call to sleepq_catch_signals() should be passed in as the - * argument. - */ -int -sleepq_calc_signal_retval(int sig) -{ - struct thread *td; - struct proc *p; - int rval; + if (td->td_flags & TDF_INTERRUPT) + return (td->td_intrval); - td = curthread; - p = td->td_proc; - PROC_LOCK(p); - mtx_lock(&p->p_sigacts->ps_mtx); - /* XXX: Should we always be calling cursig()? */ - if (sig == 0) - sig = cursig(td); - if (sig != 0) { - if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) - rval = EINTR; - else - rval = ERESTART; - } else - rval = 0; - mtx_unlock(&p->p_sigacts->ps_mtx); - PROC_UNLOCK(p); - return (rval); + return (0); } /* @@ -541,6 +517,7 @@ sleepq_wait(void *wchan) { MPASS(!(curthread->td_flags & TDF_SINTR)); + mtx_lock_spin(&sched_lock); sleepq_switch(wchan); mtx_unlock_spin(&sched_lock); } @@ -552,11 +529,18 @@ sleepq_wait(void *wchan) int sleepq_wait_sig(void *wchan) { + int rcatch; int rval; - sleepq_switch(wchan); + rcatch = sleepq_catch_signals(wchan); + if (rcatch == 0) + sleepq_switch(wchan); + else + sleepq_release(wchan); rval = sleepq_check_signals(); mtx_unlock_spin(&sched_lock); + if (rcatch) + return (rcatch); return (rval); } @@ -570,6 +554,7 @@ sleepq_timedwait(void *wchan) int rval; MPASS(!(curthread->td_flags & TDF_SINTR)); + mtx_lock_spin(&sched_lock); sleepq_switch(wchan); rval = sleepq_check_timeout(); mtx_unlock_spin(&sched_lock); @@ -581,18 +566,23 @@ sleepq_timedwait(void *wchan) * it is interrupted by a signal, or it times out waiting to be awakened. */ int -sleepq_timedwait_sig(void *wchan, int signal_caught) +sleepq_timedwait_sig(void *wchan) { - int rvalt, rvals; + int rcatch, rvalt, rvals; - sleepq_switch(wchan); + rcatch = sleepq_catch_signals(wchan); + if (rcatch == 0) + sleepq_switch(wchan); + else + sleepq_release(wchan); rvalt = sleepq_check_timeout(); rvals = sleepq_check_signals(); mtx_unlock_spin(&sched_lock); - if (signal_caught || rvalt == 0) + if (rcatch) + return (rcatch); + if (rvals) return (rvals); - else - return (rvalt); + return (rvalt); } /* @@ -825,13 +815,14 @@ sleepq_remove(struct thread *td, void *wchan) * Also, whatever the signal code does... */ void -sleepq_abort(struct thread *td) +sleepq_abort(struct thread *td, int intrval) { void *wchan; mtx_assert(&sched_lock, MA_OWNED); MPASS(TD_ON_SLEEPQ(td)); MPASS(td->td_flags & TDF_SINTR); + MPASS(intrval == EINTR || intrval == ERESTART); /* * If the TDF_TIMEOUT flag is set, just leave. A @@ -843,6 +834,10 @@ sleepq_abort(struct thread *td) CTR3(KTR_PROC, "sleepq_abort: thread %p (pid %ld, %s)", (void *)td, (long)td->td_proc->p_pid, (void *)td->td_proc->p_comm); wchan = td->td_wchan; + if (wchan != NULL) { + td->td_intrval = intrval; + td->td_flags |= TDF_SLEEPABORT; + } mtx_unlock_spin(&sched_lock); sleepq_remove(td, wchan); mtx_lock_spin(&sched_lock); |