diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2024-11-16 13:06:07 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2024-11-16 13:06:07 +0000 |
commit | 3d72bc83d0228f05114932c966838368f5c8d40b (patch) | |
tree | 6e3291e7e945762b291811732ebac472479c5a5b | |
parent | d45b15b4f90f8c15f97b3a7246112ee63e119995 (diff) |
Adjust deep logic in cursig() to handle sig_stop specially.
If any other signal is pending the stop signal should be deferred.
Now cursig() uses ffs() to select the signal and so higher numbered
signals like SIGUSR1 would be ignored when going to sleep.
So handle default stop signals specially in the deep case, stash them
and only use them if no other signal is pending.
Fix for signal-stress regress (problem reported by anton@)
With and OK mpi@
-rw-r--r-- | sys/kern/kern_sig.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 23f265c665f..abbb4ff8afc 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.349 2024/11/16 12:54:05 claudio Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.350 2024/11/16 13:06:06 claudio Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -1329,7 +1329,7 @@ int cursig(struct proc *p, struct sigctx *sctx, int deep) { struct process *pr = p->p_p; - int signum, mask, prop; + int signum, mask, keep = 0, prop; sigset_t ps_siglist; KASSERT(p == curproc); @@ -1340,9 +1340,9 @@ cursig(struct proc *p, struct sigctx *sctx, int deep) mask = SIGPENDING(p); if (pr->ps_flags & PS_PPWAIT) mask &= ~STOPSIGMASK; - if (mask == 0) /* no signal to send */ - return (0); - signum = ffs((long)mask); + signum = ffs(mask); + if (signum == 0) /* no signal to send */ + goto keep; mask = sigmask(signum); /* take the signal! */ @@ -1367,8 +1367,22 @@ cursig(struct proc *p, struct sigctx *sctx, int deep) * cursig is called again and there the signal can be * handled cleanly. */ - if (deep) + if (deep) { + /* + * Do not stop the thread here if multiple + * signals are pending and at least one of + * them would force an unwind. + * + * ffs() favors low numbered signals and + * so stop signals may be picked up before + * other pending signals. + */ + if (sctx->sig_stop && SIGPENDING(p)) { + keep |= mask; + continue; + } goto keep; + } /* * If traced, always stop, and stay stopped until released @@ -1466,7 +1480,16 @@ cursig(struct proc *p, struct sigctx *sctx, int deep) /* NOTREACHED */ keep: - atomic_setbits_int(&p->p_siglist, mask); /*leave the signal for later */ + /* + * if we stashed a stop signal but no other signal is pending + * anymore pick the stop signal up again. + */ + if (keep != 0 && signum == 0) { + signum = ffs(keep); + setsigctx(p, signum, sctx); + } + /* move the signal to p_siglist for later */ + atomic_setbits_int(&p->p_siglist, mask | keep); return (signum); } |