Index: nfsclient/nfs_krpc.c =================================================================== --- nfsclient/nfs_krpc.c (revision 243732) +++ nfsclient/nfs_krpc.c (working copy) @@ -647,7 +647,6 @@ SIGTERM, SIGHUP, SIGKILL, - SIGSTOP, SIGQUIT }; @@ -698,6 +697,7 @@ } mtx_unlock(&p->p_sigacts->ps_mtx); PROC_UNLOCK(p); + sigdeferstop(td); kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0); } @@ -707,6 +707,7 @@ if (td == NULL) td = curthread; /* XXX */ kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); + sigallowstop(td); } /* Index: kern/kern_sig.c =================================================================== --- kern/kern_sig.c (revision 243732) +++ kern/kern_sig.c (working copy) @@ -2339,6 +2337,13 @@ } /* + * Don't awaken a sleeping thread for SIGSTOP if the + * STOP signal is deferred. + */ + if ((prop & SA_STOP) && (td->td_flags & TDF_SBDRY)) + goto out; + + /* * Give low priority threads a better chance to run. */ if (td->td_priority > PUSER) @@ -2379,12 +2384,13 @@ if ((TD_IS_SLEEPING(td2) || TD_IS_SWAPPED(td2)) && (td2->td_flags & TDF_SINTR)) { if (td2->td_flags & TDF_SBDRY) { - if (TD_IS_SUSPENDED(td2)) - wakeup_swapper |= - thread_unsuspend_one(td2); - if (TD_ON_SLEEPQ(td2)) - wakeup_swapper |= - sleepq_abort(td2, ERESTART); + /* + * Once a thread is asleep with SBDRY set, + * it should never become suspended due + * to this check. + */ + KASSERT(!TD_IS_SUSPENDED(td2), + ("thread with deferred stops suspended")); } else if (!TD_IS_SUSPENDED(td2)) { thread_suspend_one(td2); } @@ -2506,7 +2512,33 @@ } +/* Defer the delivery of SIGSTOP for the current thread. */ +void +sigdeferstop(struct thread *td) +{ + + KASSERT(!(td->td_flags & TDF_SBDRY), + ("attempt to set TDF_SBDRY recursively")); + thread_lock(td); + td->td_flags |= TDF_SBDRY; + thread_unlock(td); +} + /* + * Permit the delivery of SIGSTOP for the current thread. This does + * not immediately suspend if a stop was posted. Instead, the thread + * will suspend either via ast() or a subsequent interruptible sleep. + */ +void +sigallowstop(struct thread *td) +{ + + thread_lock(td); + td->td_flags &= ~TDF_SBDRY; + thread_unlock(td); +} + +/* * If the current process has received a signal (should be caught or cause * termination, should interrupt current syscall), return the signal number. * Stop signals with default action are processed immediately, then cleared; @@ -2540,6 +2572,8 @@ if (p->p_flag & P_PPWAIT) SIG_STOPSIGMASK(sigpending); + if (td->td_flags & TDF_SBDRY) + SIG_STOPSIGMASK(sigpending); if (SIGISEMPTY(sigpending)) /* no signal to send */ return (0); sig = sig_ffs(&sigpending); @@ -2653,10 +2687,6 @@ (p->p_pgrp->pg_jobc == 0 && prop & SA_TTYSTOP)) break; /* == ignore */ - - /* Ignore, but do not drop the stop signal. */ - if (stop_allowed != SIG_STOP_ALLOWED) - return (sig); mtx_unlock(&ps->ps_mtx); WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &p->p_mtx.lock_object, "Catching SIGSTOP"); Index: kern/subr_sleepqueue.c =================================================================== --- kern/subr_sleepqueue.c (revision 243732) +++ kern/subr_sleepqueue.c (working copy) @@ -350,8 +350,6 @@ if (flags & SLEEPQ_INTERRUPTIBLE) { td->td_flags |= TDF_SINTR; td->td_flags &= ~TDF_SLEEPABORT; - if (flags & SLEEPQ_STOP_ON_BDRY) - td->td_flags |= TDF_SBDRY; } thread_unlock(td); } @@ -605,7 +601,7 @@ /* We are no longer in an interruptible sleep. */ if (td->td_flags & TDF_SINTR) - td->td_flags &= ~(TDF_SINTR | TDF_SBDRY); + td->td_flags &= ~TDF_SINTR; if (td->td_flags & TDF_SLEEPABORT) { td->td_flags &= ~TDF_SLEEPABORT; @@ -750,7 +746,7 @@ td->td_wmesg = NULL; td->td_wchan = NULL; - td->td_flags &= ~(TDF_SINTR | TDF_SBDRY); + td->td_flags &= ~TDF_SINTR; CTR3(KTR_PROC, "sleepq_wakeup: thread %p (pid %ld, %s)", (void *)td, (long)td->td_proc->p_pid, td->td_name); Index: fs/nfs/nfs_commonkrpc.c =================================================================== --- fs/nfs/nfs_commonkrpc.c (revision 243732) +++ fs/nfs/nfs_commonkrpc.c (working copy) @@ -819,7 +819,6 @@ SIGTERM, SIGHUP, SIGKILL, - SIGSTOP, SIGQUIT }; @@ -870,6 +869,7 @@ } mtx_unlock(&p->p_sigacts->ps_mtx); PROC_UNLOCK(p); + sigdeferstop(td); kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, 0); } @@ -879,6 +879,7 @@ if (td == NULL) td = curthread; /* XXX */ kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); + sigallowstop(td); } /* Index: sys/signalvar.h =================================================================== --- sys/signalvar.h (revision 243732) +++ sys/signalvar.h (working copy) @@ -326,7 +326,9 @@ /* * Machine-independent functions: */ int cursig(struct thread *td, int stop_allowed); +void sigdeferstop(struct thread *td); +void sigallowstop(struct thread *td); void execsigs(struct proc *p); void gsignal(int pgid, int sig, ksiginfo_t *ksi); void killproc(struct proc *p, char *why);