Diff below refactors routines to stop/unstop processes and save the signal
number which will/can be transmitted it in wait4(2). It does the following:
- Move the "hack" involving P_SINTR to avoid grabbing the SCHED_LOCK()
recursively inside proc_stop().
- Introduce proc_unstop(), the symmetric routine to proc_stop().
- Manipulate `ps_xsig' only in proc_stop/unstop().
Ok?
Index: kern/kern_sig.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sig.c,v
retrieving revision 1.278
diff -u -p -r1.278 kern_sig.c
--- kern/kern_sig.c 12 Mar 2021 10:13:28 -0000 1.278
+++ kern/kern_sig.c 20 Mar 2021 12:16:51 -0000
@@ -124,7 +124,7 @@ const int sigprop[NSIG + 1] = {
void setsigvec(struct proc *, int, struct sigaction *);
-void proc_stop(struct proc *p, int);
+int proc_stop(struct proc *p, int, int);
void proc_stop_sweep(void *);
void *proc_stop_si;
@@ -1061,8 +1061,7 @@ ptsignal(struct proc *p, int signum, enu
if (pr->ps_flags & PS_PPWAIT)
goto out;
atomic_clearbits_int(siglist, mask);
- pr->ps_xsig = signum;
- proc_stop(p, 0);
+ proc_stop(p, signum, 0);
goto out;
}
/*
@@ -1170,17 +1169,12 @@ out:
*
* while (signum = cursig(curproc))
* postsig(signum);
- *
- * Assumes that if the P_SINTR flag is set, we're holding both the
- * kernel and scheduler locks.
*/
int
cursig(struct proc *p)
{
struct process *pr = p->p_p;
int sigpending, signum, mask, prop;
- int dolock = (p->p_flag & P_SINTR) == 0;
- int s;
KERNEL_ASSERT_LOCKED();
@@ -1217,31 +1211,22 @@ cursig(struct proc *p)
*/
if (((pr->ps_flags & (PS_TRACED | PS_PPWAIT)) == PS_TRACED) &&
signum != SIGKILL) {
- pr->ps_xsig = signum;
single_thread_set(p, SINGLE_SUSPEND, 0);
-
- if (dolock)
- SCHED_LOCK(s);
- proc_stop(p, 1);
- if (dolock)
- SCHED_UNLOCK(s);
-
+ signum = proc_stop(p, signum, 1);
single_thread_clear(p, 0);
/*
* If we are no longer being traced, or the parent
* didn't give us a signal, look for more signals.
*/
- if ((pr->ps_flags & PS_TRACED) == 0 ||
- pr->ps_xsig == 0)
+ if ((pr->ps_flags & PS_TRACED) == 0 || signum == 0)
continue;
/*
* If the new signal is being masked, look for other
* signals.
*/
- signum = pr->ps_xsig;
mask = sigmask(signum);
if ((p->p_sigmask & mask) != 0)
continue;
@@ -1286,12 +1271,7 @@ cursig(struct proc *p)
(pr->ps_pgrp->pg_jobc == 0 &&
prop & SA_TTYSTOP))
break; /* == ignore */
- pr->ps_xsig = signum;
- if (dolock)
- SCHED_LOCK(s);
- proc_stop(p, 1);
- if (dolock)
- SCHED_UNLOCK(s);
+ proc_stop(p, signum, 1);
break;
} else if (prop & SA_IGNORE) {
/*
@@ -1331,15 +1311,21 @@ keep:
* Put the argument process into the stopped state and notify the parent
* via wakeup. Signals are handled elsewhere. The process must not be
* on the run queue.
+ *
+ * Assumes that if the P_SINTR flag is set, we're holding the scheduler
+ * lock.
*/
-void
-proc_stop(struct proc *p, int sw)
+int
+proc_stop(struct proc *p, int signum, int sw)
{
struct process *pr = p->p_p;
+ int dolock = (p->p_flag & P_SINTR) == 0;
+ int s;
-#ifdef MULTIPROCESSOR
- SCHED_ASSERT_LOCKED();
-#endif
+ pr->ps_xsig = signum;
+
+ if (dolock)
+ SCHED_LOCK(s);
p->p_stat = SSTOP;
atomic_clearbits_int(&pr->ps_flags, PS_WAITED);
@@ -1352,6 +1338,13 @@ proc_stop(struct proc *p, int sw)
softintr_schedule(proc_stop_si);
if (sw)
mi_switch();
+
+ if (dolock)
+ SCHED_UNLOCK(s);
+
+ signum = pr->ps_xsig;
+
+ return signum;
}
/*
@@ -1376,6 +1369,27 @@ proc_stop_sweep(void *v)
}
}
+void
+proc_unstop(struct proc *p, int signum)
+{
+ struct process *pr = p->p_p;
+
+ KASSERT(signum >= 0);
+ KASSERT(p->p_stat == SSTOP);
+
+ if (signum != 0)
+ pr->ps_xsig = signum;
+
+ /*
+ * If we're being traced (possibly because someone attached us
+ * while we were stopped), check for a signal from the debugger.
+ */
+ if ((pr->ps_flags & PS_TRACED) != 0 && pr->ps_xsig != 0)
+ atomic_setbits_int(&p->p_siglist, sigmask(pr->ps_xsig));
+
+ setrunnable(p);
+}
+
/*
* Take the action for the specified signal
* from the current set of pending signals.
@@ -2042,7 +2056,7 @@ single_thread_set(struct proc *p, enum s
if (q->p_flag & P_WEXIT) {
if (mode == SINGLE_EXIT) {
if (q->p_stat == SSTOP) {
- setrunnable(q);
+ proc_unstop(q, 0);
atomic_inc_int(&pr->ps_singlecount);
}
}
@@ -2069,7 +2083,7 @@ single_thread_set(struct proc *p, enum s
break;
case SSTOP:
if (mode == SINGLE_EXIT) {
- setrunnable(q);
+ proc_unstop(q, 0);
atomic_inc_int(&pr->ps_singlecount);
}
break;
@@ -2138,7 +2152,7 @@ single_thread_clear(struct proc *p, int
*/
if (q->p_stat == SSTOP && (q->p_flag & flag) == 0) {
if (q->p_wchan == 0)
- setrunnable(q);
+ proc_unstop(q, 0);
else
q->p_stat = SSLEEP;
}
Index: kern/sched_bsd.c
===================================================================
RCS file: /cvs/src/sys/kern/sched_bsd.c,v
retrieving revision 1.65
diff -u -p -r1.65 sched_bsd.c
--- kern/sched_bsd.c 10 Dec 2020 04:26:50 -0000 1.65
+++ kern/sched_bsd.c 20 Mar 2021 12:16:51 -0000
@@ -456,12 +456,6 @@ setrunnable(struct proc *p)
default:
panic("setrunnable");
case SSTOP:
- /*
- * If we're being traced (possibly because someone attached us
- * while we were stopped), check for a signal from the debugger.
- */
- if ((pr->ps_flags & PS_TRACED) != 0 && pr->ps_xsig != 0)
- atomic_setbits_int(&p->p_siglist, sigmask(pr->ps_xsig));
prio = p->p_usrpri;
unsleep(p);
break;
Index: kern/sys_process.c
===================================================================
RCS file: /cvs/src/sys/kern/sys_process.c,v
retrieving revision 1.86
diff -u -p -r1.86 sys_process.c
--- kern/sys_process.c 8 Feb 2021 10:51:02 -0000 1.86
+++ kern/sys_process.c 20 Mar 2021 12:16:51 -0000
@@ -484,9 +484,8 @@ ptrace_ctrl(struct proc *p, int req, pid
/* Finally, deliver the requested signal (or none). */
if (t->p_stat == SSTOP) {
- tr->ps_xsig = data;
SCHED_LOCK(s);
- setrunnable(t);
+ proc_unstop(t, data);
SCHED_UNLOCK(s);
} else {
if (data != 0)
Index: sys/signalvar.h
===================================================================
RCS file: /cvs/src/sys/sys/signalvar.h,v
retrieving revision 1.46
diff -u -p -r1.46 signalvar.h
--- sys/signalvar.h 4 Mar 2021 09:02:38 -0000 1.46
+++ sys/signalvar.h 20 Mar 2021 12:16:51 -0000
@@ -103,6 +103,7 @@ struct sigio_ref;
/*
* Machine-independent functions:
*/
+void proc_unstop(struct proc *, int);
int coredump(struct proc *p);
void execsigs(struct proc *p);
int cursig(struct proc *p);