Index: rpc/clnt_rc.c =================================================================== --- rpc/clnt_rc.c (revision 243732) +++ rpc/clnt_rc.c (working copy) @@ -265,7 +265,7 @@ stat = clnt_reconnect_connect(cl); if (stat == RPC_SYSTEMERROR) { error = tsleep(&fake_wchan, - rc->rc_intr ? PCATCH | PBDRY : 0, "rpccon", + rc->rc_intr ? PCATCH : 0, "rpccon", hz); if (error == EINTR || error == ERESTART) return (RPC_INTR); Index: rpc/clnt_vc.c =================================================================== --- rpc/clnt_vc.c (revision 243732) +++ rpc/clnt_vc.c (working copy) @@ -199,7 +199,7 @@ interrupted = 0; sleep_flag = PSOCK; if (intrflag != 0) - sleep_flag |= (PCATCH | PBDRY); + sleep_flag |= PCATCH; while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { error = msleep(&so->so_timeo, SOCK_MTX(so), @@ -740,7 +740,7 @@ case CLSET_INTERRUPTIBLE: if (*(int *) info) - ct->ct_waitflag = PCATCH | PBDRY; + ct->ct_waitflag = PCATCH; else ct->ct_waitflag = 0; break; 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 }; @@ -668,7 +667,7 @@ /* * The set/restore sigmask functions are used to (temporarily) overwrite - * the process p_sigmask during an RPC call (for example). These are also + * the thread td_sigmask during an RPC call (for example). These are also * used in other places in the NFS client that might tsleep(). */ void @@ -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: nfsclient/nfsmount.h =================================================================== --- nfsclient/nfsmount.h (revision 243732) +++ nfsclient/nfsmount.h (working copy) @@ -125,7 +125,7 @@ #define NFS_DEFAULT_NEGNAMETIMEO 60 #endif -#define NFS_PCATCH (PCATCH | PBDRY) +#define NFS_PCATCH (PCATCH) #endif Index: kern/kern_sig.c =================================================================== --- kern/kern_sig.c (revision 243732) +++ kern/kern_sig.c (working copy) @@ -101,7 +101,7 @@ static char *expand_name(const char *, uid_t, pid_t); static int killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi); -static int issignal(struct thread *td, int stop_allowed); +static int issignal(struct thread *td); static int sigprop(int sig); static void tdsigwakeup(struct thread *, int, sig_t, int); static void sig_suspend_threads(struct thread *, struct proc *, int); @@ -563,19 +563,17 @@ } /* - * Determine signal that should be delivered to process p, the current - * process, 0 if none. If there is a pending stop signal with default + * Determine signal that should be delivered to thread td, the current + * thread, 0 if none. If there is a pending stop signal with default * action, the process stops in issignal(). */ int -cursig(struct thread *td, int stop_allowed) +cursig(struct thread *td) { PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); - KASSERT(stop_allowed == SIG_STOP_ALLOWED || - stop_allowed == SIG_STOP_NOT_ALLOWED, ("cursig: stop_allowed")); mtx_assert(&td->td_proc->p_sigacts->ps_mtx, MA_OWNED); THREAD_LOCK_ASSERT(td, MA_NOTOWNED); - return (SIGPENDING(td) ? issignal(td, stop_allowed) : 0); + return (SIGPENDING(td) ? issignal(td) : 0); } /* @@ -1216,7 +1214,7 @@ SIG_CANTMASK(td->td_sigmask); SIGDELSET(td->td_sigmask, i); mtx_lock(&ps->ps_mtx); - sig = cursig(td, SIG_STOP_ALLOWED); + sig = cursig(td); mtx_unlock(&ps->ps_mtx); if (sig) goto out; @@ -1482,7 +1480,7 @@ /* void */; thread_suspend_check(0); mtx_lock(&p->p_sigacts->ps_mtx); - while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0) + while ((sig = cursig(td)) != 0) has_sig += postsig(sig); mtx_unlock(&p->p_sigacts->ps_mtx); } @@ -2125,9 +2123,9 @@ * Some signals have a process-wide effect and a per-thread * component. Most processing occurs when the process next * tries to cross the user boundary, however there are some - * times when processing needs to be done immediatly, such as + * times when processing needs to be done immediately, such as * waking up threads so that they can cross the user boundary. - * We try do the per-process part here. + * We try to do the per-process part here. */ if (P_SHOULDSTOP(p)) { KASSERT(!(p->p_flag & P_WEXIT), @@ -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; @@ -2519,7 +2551,7 @@ * postsig(sig); */ static int -issignal(struct thread *td, int stop_allowed) +issignal(struct thread *td) { struct proc *p; struct sigacts *ps; @@ -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/kern_synch.c =================================================================== --- kern/kern_synch.c (revision 243732) +++ kern/kern_synch.c (working copy) @@ -188,8 +188,6 @@ flags = SLEEPQ_SLEEP; if (catch) flags |= SLEEPQ_INTERRUPTIBLE; - if (priority & PBDRY) - flags |= SLEEPQ_STOP_ON_BDRY; sleepq_lock(ident); CTR5(KTR_PROC, "sleep: thread %ld (pid %ld, %s) on %s (%p)", Index: kern/subr_trap.c =================================================================== --- kern/subr_trap.c (revision 243732) +++ kern/subr_trap.c (working copy) @@ -226,7 +226,7 @@ !SIGISEMPTY(p->p_siglist)) { PROC_LOCK(p); mtx_lock(&p->p_sigacts->ps_mtx); - while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0) + while ((sig = cursig(td)) != 0) postsig(sig); mtx_unlock(&p->p_sigacts->ps_mtx); PROC_UNLOCK(p); 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); } @@ -405,7 +403,7 @@ struct thread *td; struct proc *p; struct sigacts *ps; - int sig, ret, stop_allowed; + int sig, ret; td = curthread; p = curproc; @@ -422,8 +420,6 @@ sleepq_switch(wchan, pri); return (0); } - stop_allowed = (td->td_flags & TDF_SBDRY) ? SIG_STOP_NOT_ALLOWED : - SIG_STOP_ALLOWED; thread_unlock(td); mtx_unlock_spin(&sc->sc_lock); CTR3(KTR_PROC, "sleepq catching signals: thread %p (pid %ld, %s)", @@ -431,7 +427,7 @@ PROC_LOCK(p); ps = p->p_sigacts; mtx_lock(&ps->ps_mtx); - sig = cursig(td, stop_allowed); + sig = cursig(td); if (sig == 0) { mtx_unlock(&ps->ps_mtx); ret = thread_suspend_check(1); @@ -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/nfsport.h =================================================================== --- fs/nfs/nfsport.h (revision 243732) +++ fs/nfs/nfsport.h (working copy) @@ -901,7 +901,7 @@ * while holding a resource that other threads would block for, such as * a vnode lock. */ -#define NFS_PCATCH (PCATCH | PBDRY) +#define NFS_PCATCH (PCATCH) #endif /* _KERNEL */ 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 }; @@ -840,7 +839,7 @@ /* * The set/restore sigmask functions are used to (temporarily) overwrite - * the process p_sigmask during an RPC call (for example). These are also + * the thread td_sigmask during an RPC call (for example). These are also * used in other places in the NFS client that might tsleep(). */ void @@ -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: cddl/compat/opensolaris/sys/sig.h =================================================================== --- cddl/compat/opensolaris/sys/sig.h (revision 243732) +++ cddl/compat/opensolaris/sys/sig.h (working copy) @@ -55,7 +55,7 @@ p = td->td_proc; PROC_LOCK(p); mtx_lock(&p->p_sigacts->ps_mtx); - sig = cursig(td, SIG_STOP_ALLOWED); + sig = cursig(td); mtx_unlock(&p->p_sigacts->ps_mtx); PROC_UNLOCK(p); if (sig != 0) 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); +int cursig(struct thread *td); +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); Index: sys/param.h =================================================================== --- sys/param.h (revision 243732) +++ sys/param.h (working copy) @@ -192,7 +192,6 @@ #define PRIMASK 0x0ff #define PCATCH 0x100 /* OR'd with pri for tsleep to check signals */ #define PDROP 0x200 /* OR'd with pri to stop re-entry of interlock mutex */ -#define PBDRY 0x400 /* for PCATCH stop is done on the user boundary */ #define NZERO 0 /* default "nice" */ Index: sys/sleepqueue.h =================================================================== --- sys/sleepqueue.h (revision 243732) +++ sys/sleepqueue.h (working copy) @@ -93,8 +93,6 @@ #define SLEEPQ_SX 0x03 /* Used by an sx lock. */ #define SLEEPQ_LK 0x04 /* Used by a lockmgr. */ #define SLEEPQ_INTERRUPTIBLE 0x100 /* Sleep is interruptible. */ -#define SLEEPQ_STOP_ON_BDRY 0x200 /* Stop sleeping thread on - user mode boundary */ void init_sleepqueues(void); int sleepq_abort(struct thread *td, int intrval);