Index: sys/proc.h =================================================================== RCS file: /home/ncvs/src/sys/sys/proc.h,v retrieving revision 1.452 diff -u -r1.452 proc.h --- sys/proc.h 11 Feb 2006 09:33:07 -0000 1.452 +++ sys/proc.h 14 Feb 2006 04:45:46 -0000 @@ -343,7 +343,7 @@ #define TDF_TIMEOUT 0x00000010 /* Timing out during sleep. */ #define TDF_IDLETD 0x00000020 /* This is a per-CPU idle thread. */ #define TDF_SELECT 0x00000040 /* Selecting; wakeup/waiting danger. */ -#define TDF_UNUSED7 0x00000080 /* --available -- */ +#define TDF_SLEEPABORT 0x00000080 /* sleepq_abort was called. */ #define TDF_TSNOBLOCK 0x00000100 /* Don't block on a turnstile due to race. */ #define TDF_UNUSED9 0x00000200 /* --available -- */ #define TDF_BOUNDARY 0x00000400 /* Thread suspended at user boundary */ Index: sys/sleepqueue.h =================================================================== RCS file: /home/ncvs/src/sys/sys/sleepqueue.h,v retrieving revision 1.6 diff -u -r1.6 sleepqueue.h --- sys/sleepqueue.h 7 Jan 2005 02:29:24 -0000 1.6 +++ sys/sleepqueue.h 14 Feb 2006 04:45:47 -0000 @@ -87,12 +87,10 @@ #define SLEEPQ_INTERRUPTIBLE 0x100 /* Sleep is interruptible. */ void init_sleepqueues(void); -void sleepq_abort(struct thread *td); +void sleepq_abort(struct thread *td, int intrval); void sleepq_add(void *, struct mtx *, const char *, int); struct sleepqueue *sleepq_alloc(void); void sleepq_broadcast(void *, int, int); -int sleepq_calc_signal_retval(int sig); -int sleepq_catch_signals(void *wchan); void sleepq_free(struct sleepqueue *); void sleepq_lock(void *); struct sleepqueue *sleepq_lookup(void *); @@ -101,7 +99,7 @@ void sleepq_signal(void *, int, int); void sleepq_set_timeout(void *wchan, int timo); int sleepq_timedwait(void *wchan); -int sleepq_timedwait_sig(void *wchan, int signal_caught); +int sleepq_timedwait_sig(void *wchan); void sleepq_wait(void *); int sleepq_wait_sig(void *wchan); Index: kern/kern_condvar.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_condvar.c,v retrieving revision 1.53 diff -u -r1.53 kern_condvar.c --- kern/kern_condvar.c 12 Dec 2005 00:02:22 -0000 1.53 +++ kern/kern_condvar.c 14 Feb 2006 04:45:47 -0000 @@ -166,7 +166,7 @@ { struct thread *td; struct proc *p; - int rval, sig; + int rval; WITNESS_SAVE_DECL(mp); td = curthread; @@ -210,10 +210,7 @@ sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR | SLEEPQ_INTERRUPTIBLE); - sig = sleepq_catch_signals(cvp); rval = sleepq_wait_sig(cvp); - if (rval == 0) - rval = sleepq_calc_signal_retval(sig); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) @@ -292,7 +289,6 @@ struct thread *td; struct proc *p; int rval; - int sig; WITNESS_SAVE_DECL(mp); td = curthread; @@ -338,10 +334,7 @@ sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR | SLEEPQ_INTERRUPTIBLE); sleepq_set_timeout(cvp, timo); - sig = sleepq_catch_signals(cvp); - rval = sleepq_timedwait_sig(cvp, sig != 0); - if (rval == 0) - rval = sleepq_calc_signal_retval(sig); + rval = sleepq_timedwait_sig(cvp); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) Index: kern/kern_kse.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_kse.c,v retrieving revision 1.221 diff -u -r1.221 kern_kse.c --- kern/kern_kse.c 6 Feb 2006 22:06:54 -0000 1.221 +++ kern/kern_kse.c 14 Feb 2006 04:45:48 -0000 @@ -223,7 +223,7 @@ else td2->td_intrval = ERESTART; if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR)) - sleepq_abort(td2); + sleepq_abort(td2, td2->td_intrval); mtx_unlock_spin(&sched_lock); } PROC_UNLOCK(p); Index: kern/kern_sig.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_sig.c,v retrieving revision 1.321 diff -u -r1.321 kern_sig.c --- kern/kern_sig.c 13 Feb 2006 03:16:55 -0000 1.321 +++ kern/kern_sig.c 14 Feb 2006 04:45:49 -0000 @@ -90,7 +90,7 @@ static int killpg1(struct thread *td, int sig, int pgid, int all); static int issignal(struct thread *p); static int sigprop(int sig); -static void tdsigwakeup(struct thread *, int, sig_t); +static void tdsigwakeup(struct thread *, int, sig_t, int); static void sig_suspend_threads(struct thread *, struct proc *, int); static int filt_sigattach(struct knote *kn); static void filt_sigdetach(struct knote *kn); @@ -2049,6 +2049,7 @@ sigqueue_t *sigqueue; int prop; struct sigacts *ps; + int intrval; int ret = 0; PROC_LOCK_ASSERT(p, MA_OWNED); @@ -2109,6 +2110,10 @@ action = SIG_CATCH; else action = SIG_DFL; + if (SIGISMEMBER(ps->ps_sigintr, sig)) + intrval = EINTR; + else + intrval = ERESTART; mtx_unlock(&ps->ps_mtx); if (prop & SA_CONT) @@ -2253,7 +2258,7 @@ */ mtx_lock_spin(&sched_lock); if (TD_ON_SLEEPQ(td) && (td->td_flags & TDF_SINTR)) - sleepq_abort(td); + sleepq_abort(td, intrval); mtx_unlock_spin(&sched_lock); goto out; /* @@ -2263,7 +2268,7 @@ } else if (p->p_state == PRS_NORMAL) { if (p->p_flag & P_TRACED || action == SIG_CATCH) { mtx_lock_spin(&sched_lock); - tdsigwakeup(td, sig, action); + tdsigwakeup(td, sig, action, intrval); mtx_unlock_spin(&sched_lock); goto out; } @@ -2308,7 +2313,7 @@ runfast: mtx_lock_spin(&sched_lock); - tdsigwakeup(td, sig, action); + tdsigwakeup(td, sig, action, intrval); thread_unsuspend(p); mtx_unlock_spin(&sched_lock); out: @@ -2323,7 +2328,7 @@ * out of any sleep it may be in etc. */ static void -tdsigwakeup(struct thread *td, int sig, sig_t action) +tdsigwakeup(struct thread *td, int sig, sig_t action, int intrval) { struct proc *p = td->td_proc; register int prop; @@ -2375,7 +2380,7 @@ if (td->td_priority > PUSER) sched_prio(td, PUSER); - sleepq_abort(td); + sleepq_abort(td, intrval); } else { /* * Other states do nothing with the signal immediately, Index: kern/kern_synch.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_synch.c,v retrieving revision 1.275 diff -u -r1.275 kern_synch.c --- kern/kern_synch.c 11 Feb 2006 09:33:06 -0000 1.275 +++ kern/kern_synch.c 14 Feb 2006 04:45:49 -0000 @@ -124,7 +124,7 @@ { struct thread *td; struct proc *p; - int catch, rval, sig, flags; + int catch, rval, flags; WITNESS_SAVE_DECL(mtx); td = curthread; @@ -205,10 +205,6 @@ sleepq_add(ident, mtx, wmesg, flags); if (timo) sleepq_set_timeout(ident, timo); - if (catch) { - sig = sleepq_catch_signals(ident); - } else - sig = 0; /* * Adjust this thread's priority. @@ -218,7 +214,7 @@ mtx_unlock_spin(&sched_lock); if (timo && catch) - rval = sleepq_timedwait_sig(ident, sig != 0); + rval = sleepq_timedwait_sig(ident); else if (timo) rval = sleepq_timedwait(ident); else if (catch) @@ -227,8 +223,6 @@ sleepq_wait(ident); rval = 0; } - if (rval == 0 && catch) - rval = sleepq_calc_signal_retval(sig); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(0, 0); Index: kern/kern_thread.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_thread.c,v retrieving revision 1.228 diff -u -r1.228 kern_thread.c --- kern/kern_thread.c 13 Feb 2006 03:16:55 -0000 1.228 +++ kern/kern_thread.c 14 Feb 2006 04:45:49 -0000 @@ -762,7 +762,7 @@ thread_unsuspend_one(td2); if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR)) - sleepq_abort(td2); + sleepq_abort(td2, EINTR); break; case SINGLE_BOUNDARY: if (TD_IS_SUSPENDED(td2) && @@ -770,7 +770,7 @@ thread_unsuspend_one(td2); if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR)) - sleepq_abort(td2); + sleepq_abort(td2, ERESTART); break; default: if (TD_IS_SUSPENDED(td2)) @@ -894,12 +894,12 @@ return (0); /* Exempt from stopping. */ } if ((p->p_flag & P_SINGLE_EXIT) && return_instead) - return (1); + return (EINTR); /* Should we goto user boundary if we didn't come from there? */ if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE && (p->p_flag & P_SINGLE_BOUNDARY) && return_instead) - return (1); + return (ERESTART); /* If thread will exit, flush its pending signals */ if ((p->p_flag & P_SINGLE_EXIT) && (p->p_singlethread != td)) Index: kern/subr_sleepqueue.c =================================================================== RCS file: /home/ncvs/src/sys/kern/subr_sleepqueue.c,v retrieving revision 1.23 diff -u -r1.23 subr_sleepqueue.c --- kern/subr_sleepqueue.c 28 Jan 2006 00:49:31 -0000 1.23 +++ kern/subr_sleepqueue.c 14 Feb 2006 04:45:50 -0000 @@ -318,8 +318,10 @@ 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 @@ /* * 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 @@ 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 @@ 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 @@ 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 @@ { MPASS(!(curthread->td_flags & TDF_SINTR)); + mtx_lock_spin(&sched_lock); sleepq_switch(wchan); mtx_unlock_spin(&sched_lock); } @@ -552,11 +529,18 @@ 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 @@ 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 @@ * 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 @@ * 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 @@ 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);