diff --git a/sys/cddl/compat/opensolaris/sys/sig.h b/sys/cddl/compat/opensolaris/sys/sig.h index 985896e..5053797 100644 --- a/sys/cddl/compat/opensolaris/sys/sig.h +++ b/sys/cddl/compat/opensolaris/sys/sig.h @@ -55,7 +55,7 @@ issig(int why) p = td->td_proc; PROC_LOCK(p); mtx_lock(&p->p_sigacts->ps_mtx); - sig = cursig(td); + sig = cursig(td, SIG_STOP_ALLOWED); mtx_unlock(&p->p_sigacts->ps_mtx); PROC_UNLOCK(p); if (sig != 0) diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 3225754..cdf757d 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -100,7 +100,7 @@ SDT_PROBE_ARGTYPE(proc, kernel, , signal_discard, 2, "int"); static int coredump(struct thread *); static char *expand_name(const char *, uid_t, pid_t); static int killpg1(struct thread *td, int sig, int pgid, int all); -static int issignal(struct thread *p); +static int issignal(struct thread *td, int stop_allowed); static int sigprop(int sig); static void tdsigwakeup(struct thread *, int, sig_t, int); static void sig_suspend_threads(struct thread *, struct proc *, int); @@ -558,12 +558,14 @@ sigqueue_delete_stopmask_proc(struct proc *p) * action, the process stops in issignal(). */ int -cursig(struct thread *td) +cursig(struct thread *td, int stop_allowed) { 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) : 0); + return (SIGPENDING(td) ? issignal(td, stop_allowed) : 0); } /* @@ -1191,7 +1193,7 @@ restart: SIG_CANTMASK(td->td_sigmask); SIGDELSET(td->td_sigmask, i); mtx_lock(&ps->ps_mtx); - sig = cursig(td); + sig = cursig(td, SIG_STOP_ALLOWED); mtx_unlock(&ps->ps_mtx); if (sig) goto out; @@ -2310,18 +2312,28 @@ static void sig_suspend_threads(struct thread *td, struct proc *p, int sending) { struct thread *td2; + int wakeup_swapper; PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK_ASSERT(p, MA_OWNED); + wakeup_swapper = 0; FOREACH_THREAD_IN_PROC(p, td2) { thread_lock(td2); td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; if ((TD_IS_SLEEPING(td2) || TD_IS_SWAPPED(td2)) && - (td2->td_flags & TDF_SINTR) && - !TD_IS_SUSPENDED(td2)) { - thread_suspend_one(td2); - } else { + (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); + } else if (!TD_IS_SUSPENDED(td2)) { + thread_suspend_one(td2); + } + } else if (!TD_IS_SUSPENDED(td2)) { if (sending || td != td2) td2->td_flags |= TDF_ASTPENDING; #ifdef SMP @@ -2331,6 +2343,8 @@ sig_suspend_threads(struct thread *td, struct proc *p, int sending) } thread_unlock(td2); } + if (wakeup_swapper) + kick_proc0(); } int @@ -2387,8 +2401,7 @@ stopme: * postsig(sig); */ static int -issignal(td) - struct thread *td; +issignal(struct thread *td, int stop_allowed) { struct proc *p; struct sigacts *ps; @@ -2506,6 +2519,10 @@ issignal(td) (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"); diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index b91c1a5..30a8bb3 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -188,6 +188,8 @@ _sleep(void *ident, struct lock_object *lock, int priority, 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)", @@ -347,8 +349,11 @@ wakeup(void *ident) sleepq_lock(ident); wakeup_swapper = sleepq_broadcast(ident, SLEEPQ_SLEEP, 0, 0); sleepq_release(ident); - if (wakeup_swapper) + if (wakeup_swapper) { + KASSERT(ident != &proc0, + ("wakeup and wakeup_swapper and proc0")); kick_proc0(); + } } /* diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index bb8779b..d47bd8c 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -504,6 +504,22 @@ thread_unlink(struct thread *td) /* Must NOT clear links to proc! */ } +static int +calc_remaining(struct proc *p, int mode) +{ + int remaining; + + if (mode == SINGLE_EXIT) + remaining = p->p_numthreads; + else if (mode == SINGLE_BOUNDARY) + remaining = p->p_numthreads - p->p_boundary_count; + else if (mode == SINGLE_NO_EXIT) + remaining = p->p_numthreads - p->p_suspcount; + else + panic("calc_remaining: wrong mode %d", mode); + return (remaining); +} + /* * Enforce single-threading. * @@ -551,12 +567,7 @@ thread_single(int mode) p->p_flag |= P_STOPPED_SINGLE; PROC_SLOCK(p); p->p_singlethread = td; - if (mode == SINGLE_EXIT) - remaining = p->p_numthreads; - else if (mode == SINGLE_BOUNDARY) - remaining = p->p_numthreads - p->p_boundary_count; - else - remaining = p->p_numthreads - p->p_suspcount; + remaining = calc_remaining(p, mode); while (remaining != 1) { if (P_SHOULDSTOP(p) != P_STOPPED_SINGLE) goto stopme; @@ -587,18 +598,17 @@ thread_single(int mode) wakeup_swapper |= sleepq_abort(td2, ERESTART); break; + case SINGLE_NO_EXIT: + if (TD_IS_SUSPENDED(td2) && + !(td2->td_flags & TDF_BOUNDARY)) + wakeup_swapper |= + thread_unsuspend_one(td2); + if (TD_ON_SLEEPQ(td2) && + (td2->td_flags & TDF_SINTR)) + wakeup_swapper |= + sleepq_abort(td2, ERESTART); + break; default: - if (TD_IS_SUSPENDED(td2)) { - thread_unlock(td2); - continue; - } - /* - * maybe other inhibited states too? - */ - if ((td2->td_flags & TDF_SINTR) && - (td2->td_inhibitors & - (TDI_SLEEPING | TDI_SWAPPED))) - thread_suspend_one(td2); break; } } @@ -611,12 +621,7 @@ thread_single(int mode) } if (wakeup_swapper) kick_proc0(); - if (mode == SINGLE_EXIT) - remaining = p->p_numthreads; - else if (mode == SINGLE_BOUNDARY) - remaining = p->p_numthreads - p->p_boundary_count; - else - remaining = p->p_numthreads - p->p_suspcount; + remaining = calc_remaining(p, mode); /* * Maybe we suspended some threads.. was it enough? @@ -630,12 +635,7 @@ stopme: * In the mean time we suspend as well. */ thread_suspend_switch(td); - if (mode == SINGLE_EXIT) - remaining = p->p_numthreads; - else if (mode == SINGLE_BOUNDARY) - remaining = p->p_numthreads - p->p_boundary_count; - else - remaining = p->p_numthreads - p->p_suspcount; + remaining = calc_remaining(p, mode); } if (mode == SINGLE_EXIT) { /* diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index 01fcc73..b3ae6fd 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -341,6 +341,8 @@ sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags, 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); } @@ -378,7 +380,7 @@ sleepq_catch_signals(void *wchan, int pri) struct thread *td; struct proc *p; struct sigacts *ps; - int sig, ret; + int sig, ret, stop_allowed; td = curthread; p = curproc; @@ -395,6 +397,8 @@ sleepq_catch_signals(void *wchan, int pri) 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)", @@ -402,7 +406,7 @@ sleepq_catch_signals(void *wchan, int pri) PROC_LOCK(p); ps = p->p_sigacts; mtx_lock(&ps->ps_mtx); - sig = cursig(td); + sig = cursig(td, stop_allowed); if (sig == 0) { mtx_unlock(&ps->ps_mtx); ret = thread_suspend_check(1); @@ -560,7 +564,7 @@ sleepq_check_signals(void) /* We are no longer in an interruptible sleep. */ if (td->td_flags & TDF_SINTR) - td->td_flags &= ~TDF_SINTR; + td->td_flags &= ~(TDF_SINTR | TDF_SBDRY); if (td->td_flags & TDF_SLEEPABORT) { td->td_flags &= ~TDF_SLEEPABORT; @@ -682,7 +686,7 @@ sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, int pri) td->td_wmesg = NULL; td->td_wchan = NULL; - td->td_flags &= ~TDF_SINTR; + td->td_flags &= ~(TDF_SINTR | TDF_SBDRY); CTR3(KTR_PROC, "sleepq_wakeup: thread %p (pid %ld, %s)", (void *)td, (long)td->td_proc->p_pid, td->td_name); diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 0f4636e..6d60ddb 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -221,7 +221,7 @@ ast(struct trapframe *framep) if (flags & TDF_NEEDSIGCHK) { PROC_LOCK(p); mtx_lock(&p->p_sigacts->ps_mtx); - while ((sig = cursig(td)) != 0) + while ((sig = cursig(td, SIG_STOP_ALLOWED)) != 0) postsig(sig); mtx_unlock(&p->p_sigacts->ps_mtx); PROC_UNLOCK(p); diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index c803d68..945bc51 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -1254,7 +1254,7 @@ nfs_getcacheblk(struct vnode *vp, daddr_t bn, int size, struct thread *td) sigset_t oldset; nfs_set_sigmask(td, &oldset); - bp = getblk(vp, bn, size, PCATCH, 0, 0); + bp = getblk(vp, bn, size, NFS_PCATCH, 0, 0); nfs_restore_sigmask(td, &oldset); while (bp == NULL) { if (nfs_sigintr(nmp, td)) @@ -1291,7 +1291,7 @@ nfs_vinvalbuf(struct vnode *vp, int flags, struct thread *td, int intrflg) if ((nmp->nm_flag & NFSMNT_INT) == 0) intrflg = 0; if (intrflg) { - slpflag = PCATCH; + slpflag = NFS_PCATCH; slptimeo = 2 * hz; } else { slpflag = 0; @@ -1370,7 +1370,7 @@ nfs_asyncio(struct nfsmount *nmp, struct buf *bp, struct ucred *cred, struct thr } again: if (nmp->nm_flag & NFSMNT_INT) - slpflag = PCATCH; + slpflag = NFS_PCATCH; gotiod = FALSE; /* @@ -1439,7 +1439,7 @@ again: mtx_unlock(&nfs_iod_mtx); return (error2); } - if (slpflag == PCATCH) { + if (slpflag == NFS_PCATCH) { slpflag = 0; slptimeo = 2 * hz; } diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index 07a7904..f865384 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -2936,7 +2936,7 @@ nfs_flush(struct vnode *vp, int waitfor, int commit) int bvecsize = 0, bveccount; if (nmp->nm_flag & NFSMNT_INT) - slpflag = PCATCH; + slpflag = NFS_PCATCH; if (!commit) passone = 0; bo = &vp->v_bufobj; @@ -3134,7 +3134,7 @@ loop: error = EINTR; goto done; } - if (slpflag == PCATCH) { + if (slpflag & PCATCH) { slpflag = 0; slptimeo = 2 * hz; } @@ -3172,7 +3172,7 @@ loop: error = nfs_sigintr(nmp, td); if (error) goto done; - if (slpflag == PCATCH) { + if (slpflag & PCATCH) { slpflag = 0; slptimeo = 2 * hz; } diff --git a/sys/nfsclient/nfsmount.h b/sys/nfsclient/nfsmount.h index 99d12d9..47d7ef3 100644 --- a/sys/nfsclient/nfsmount.h +++ b/sys/nfsclient/nfsmount.h @@ -107,6 +107,8 @@ struct nfsmount { #define NFS_TPRINTF_DELAY 30 #endif +#define NFS_PCATCH (PCATCH | PBDRY) + #endif #endif diff --git a/sys/rpc/clnt_rc.c b/sys/rpc/clnt_rc.c index 5e80d05..217608c 100644 --- a/sys/rpc/clnt_rc.c +++ b/sys/rpc/clnt_rc.c @@ -264,7 +264,8 @@ clnt_reconnect_call( stat = clnt_reconnect_connect(cl); if (stat == RPC_SYSTEMERROR) { error = tsleep(&fake_wchan, - rc->rc_intr ? PCATCH : 0, "rpccon", hz); + rc->rc_intr ? PCATCH | PBDRY : 0, "rpccon", + hz); if (error == EINTR || error == ERESTART) return (RPC_INTR); tries++; diff --git a/sys/rpc/clnt_vc.c b/sys/rpc/clnt_vc.c index 4e732f2..3f15c43 100644 --- a/sys/rpc/clnt_vc.c +++ b/sys/rpc/clnt_vc.c @@ -196,7 +196,7 @@ clnt_vc_create( while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { error = msleep(&so->so_timeo, SOCK_MTX(so), - PSOCK | PCATCH, "connec", 0); + PSOCK | PCATCH | PBDRY, "connec", 0); if (error) { if (error == EINTR || error == ERESTART) interrupted = 1; @@ -477,6 +477,7 @@ call_again: errp->re_errno = error; switch (error) { case EINTR: + case ERESTART: stat = RPC_INTR; break; case EWOULDBLOCK: @@ -709,7 +710,7 @@ clnt_vc_control(CLIENT *cl, u_int request, void *info) case CLSET_INTERRUPTIBLE: if (*(int *) info) - ct->ct_waitflag = PCATCH; + ct->ct_waitflag = PCATCH | PBDRY; else ct->ct_waitflag = 0; break; diff --git a/sys/sys/param.h b/sys/sys/param.h index dffedb2..225faf9 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -187,6 +187,7 @@ #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" */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 0a4b79c..b65db62 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -320,7 +320,7 @@ do { \ #define TDF_BOUNDARY 0x00000400 /* Thread suspended at user boundary */ #define TDF_ASTPENDING 0x00000800 /* Thread has some asynchronous events. */ #define TDF_TIMOFAIL 0x00001000 /* Timeout from sleep after we were awake. */ -#define TDF_UNUSED2000 0x00002000 /* --available-- */ +#define TDF_SBDRY 0x00002000 /* Stop only on usermode boundary. */ #define TDF_UPIBLOCKED 0x00004000 /* Thread blocked on user PI mutex. */ #define TDF_NEEDSUSPCHK 0x00008000 /* Thread may need to suspend. */ #define TDF_NEEDRESCHED 0x00010000 /* Thread needs to yield. */ diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index dc09226..89b40f0 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -311,10 +311,14 @@ extern int kern_logsigexit; /* Sysctl variable kern.logsigexit */ #define SIGIO_LOCKED() mtx_owned(&sigio_lock) #define SIGIO_ASSERT(type) mtx_assert(&sigio_lock, type) +/* stop_allowed parameter for cursig */ +#define SIG_STOP_ALLOWED 100 +#define SIG_STOP_NOT_ALLOWED 101 + /* * Machine-independent functions: */ -int cursig(struct thread *td); +int cursig(struct thread *td, int stop_allowed); void execsigs(struct proc *p); void gsignal(int pgid, int sig); void killproc(struct proc *p, char *why); diff --git a/sys/sys/sleepqueue.h b/sys/sys/sleepqueue.h index 0d1f361..362945a 100644 --- a/sys/sys/sleepqueue.h +++ b/sys/sys/sleepqueue.h @@ -93,6 +93,8 @@ struct thread; #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);