Shortcut cursig when called during sleep setup.
authorclaudio <claudio@openbsd.org>
Thu, 17 Oct 2024 09:11:35 +0000 (09:11 +0000)
committerclaudio <claudio@openbsd.org>
Thu, 17 Oct 2024 09:11:35 +0000 (09:11 +0000)
Add deep flag as function argument which is used by the sleep API but
nowhere else. Both calls to sleep_signal_check() should skip the ugly
bits of cursig().

In cursig() if deep once it is clear a signal will be taken keep the
signal on the thread siglist and return. sleep_signal_check() will then
return EINTR or ERESTART based on the signal context.  There is no reason
to do more in this special case. Especially stop/cont and the ptrace trap
must be skipped here. Once the call makes it to userret the signal will be
picked up again and handled in a safe location.

Stopping singals need some additional logic since we don't want to abort
the sleep just to stop a process. Since our SIGSTOP handling requires
a major rewrite this will be posponed until then.

OK mpi@

sys/kern/kern_sig.c
sys/kern/kern_synch.c
sys/sys/signalvar.h
sys/ufs/mfs/mfs_vfsops.c

index c057609..98edd73 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_sig.c,v 1.342 2024/10/15 13:49:26 claudio Exp $  */
+/*     $OpenBSD: kern_sig.c,v 1.343 2024/10/17 09:11:35 claudio Exp $  */
 /*     $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $   */
 
 /*
@@ -1302,14 +1302,14 @@ setsigctx(struct proc *p, int signum, struct sigctx *sctx)
  * they aren't returned.  This is checked after each entry to the system for
  * a syscall or trap. The normal call sequence is
  *
- *     while (signum = cursig(curproc, &ctx))
+ *     while (signum = cursig(curproc, &ctx, 0))
  *             postsig(signum, &ctx);
  *
  * Assumes that if the P_SINTR flag is set, we're holding both the
  * kernel and scheduler locks.
  */
 int
-cursig(struct proc *p, struct sigctx *sctx)
+cursig(struct proc *p, struct sigctx *sctx, int deep)
 {
        struct process *pr = p->p_p;
        int signum, mask, prop;
@@ -1344,6 +1344,15 @@ cursig(struct proc *p, struct sigctx *sctx)
                if (sctx->sig_ignore && (pr->ps_flags & PS_TRACED) == 0)
                        continue;
 
+               /*
+                * If cursig is called while going to sleep, abort now
+                * and stop the sleep. When the call unwinded to userret
+                * cursig is called again and there the signal can be
+                * handled cleanly.
+                */
+               if (deep)
+                       goto keep;
+
                /*
                 * If traced, always stop, and stay stopped until released
                 * by the debugger.  If our parent process is waiting for
@@ -1915,7 +1924,7 @@ sys___thrsigdivert(struct proc *p, void *v, register_t *retval)
 
        dosigsuspend(p, p->p_sigmask &~ mask);
        for (;;) {
-               si.si_signo = cursig(p, &ctx);
+               si.si_signo = cursig(p, &ctx, 0);
                if (si.si_signo != 0) {
                        sigset_t smask = sigmask(si.si_signo);
                        if (smask & mask) {
@@ -2006,7 +2015,7 @@ userret(struct proc *p)
        }
 
        if (SIGPENDING(p) != 0) {
-               while ((signum = cursig(p, &ctx)) != 0)
+               while ((signum = cursig(p, &ctx, 0)) != 0)
                        postsig(p, signum, &ctx);
        }
 
@@ -2020,7 +2029,7 @@ userret(struct proc *p)
                p->p_sigmask = p->p_oldmask;
                atomic_clearbits_int(&p->p_flag, P_SIGSUSPEND);
 
-               while ((signum = cursig(p, &ctx)) != 0)
+               while ((signum = cursig(p, &ctx, 0)) != 0)
                        postsig(p, signum, &ctx);
        }
 
index cbbb473..dda123c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_synch.c,v 1.206 2024/07/23 08:38:02 claudio Exp $        */
+/*     $OpenBSD: kern_synch.c,v 1.207 2024/10/17 09:11:35 claudio Exp $        */
 /*     $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */
 
 /*
@@ -458,7 +458,7 @@ sleep_signal_check(struct proc *p)
 
        if ((err = single_thread_check(p, 1)) != 0)
                return err;
-       if ((sig = cursig(p, &ctx)) != 0) {
+       if ((sig = cursig(p, &ctx, 1)) != 0) {
                if (ctx.sig_intr)
                        return EINTR;
                else
index a8c6168..c207cff 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: signalvar.h,v 1.55 2024/10/09 08:39:49 claudio Exp $  */
+/*     $OpenBSD: signalvar.h,v 1.56 2024/10/17 09:11:35 claudio Exp $  */
 /*     $NetBSD: signalvar.h,v 1.17 1996/04/22 01:23:31 christos Exp $  */
 
 /*
@@ -109,7 +109,7 @@ struct sigctx {
  */
 int    coredump(struct proc *p);
 void   execsigs(struct proc *p);
-int    cursig(struct proc *p, struct sigctx *);
+int    cursig(struct proc *p, struct sigctx *, int);
 void   pgsigio(struct sigio_ref *sir, int sig, int checkctty);
 void   pgsignal(struct pgrp *pgrp, int sig, int checkctty);
 void   psignal(struct proc *p, int sig);
index ff6d469..4ce1859 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mfs_vfsops.c,v 1.62 2022/02/14 11:26:05 claudio Exp $ */
+/*     $OpenBSD: mfs_vfsops.c,v 1.63 2024/10/17 09:11:35 claudio Exp $ */
 /*     $NetBSD: mfs_vfsops.c,v 1.10 1996/02/09 22:31:28 christos Exp $ */
 
 /*
@@ -189,7 +189,7 @@ mfs_start(struct mount *mp, int flags, struct proc *p)
                 * EINTR/ERESTART.
                 */
                if (sleepreturn != 0) {
-                       sig = cursig(p, &ctx);
+                       sig = cursig(p, &ctx, 0);
                        if (vfs_busy(mp, VB_WRITE|VB_NOWAIT) ||
                            dounmount(mp, (sig == SIGKILL) ? MNT_FORCE : 0, p))
                                atomic_clearbits_int(&p->p_siglist,