Download raw body.
fix stop signal delivery
On Tue, Feb 18, 2025 at 03:52:49PM +0100, Claudio Jeker wrote:
> On Mon, Feb 10, 2025 at 07:49:39AM +0100, Claudio Jeker wrote:
> > On Tue, Feb 04, 2025 at 03:02:06PM +0100, Claudio Jeker wrote:
> > > Long story short, stop signals (SIGSTOP and SIGTTIN, SIGTTOU and SIGTSTP)
> > > are busted for multithreaded processes (e.g. mpv needs workarounds because
> > > of that).
> > >
> > > This diff fixes this by totally reworking the way processes are stopped.
> > > Now this diff is too big to go in like this but it would be great if
> > > people could try this out. Especially if you have problems with stop
> > > signals or also when you debug multithreaded processes with egdb.
> >
> > Updated diff now that the first bits of this have been committed.
>
> This is the latest version of this diff.
New version that fixes a race in proc_stop().
This has been stable for me even when hammering the system with
signal-stress over and over again.
--
:wq Claudio
Index: dev/dt/dt_prov_static.c
===================================================================
RCS file: /cvs/src/sys/dev/dt/dt_prov_static.c,v
diff -u -p -r1.24 dt_prov_static.c
--- dev/dt/dt_prov_static.c 9 Jan 2025 17:43:33 -0000 1.24
+++ dev/dt/dt_prov_static.c 20 Feb 2025 12:33:50 -0000
@@ -44,9 +44,11 @@ DT_STATIC_PROBE2(sched, off__cpu, "pid_t
DT_STATIC_PROBE0(sched, on__cpu);
DT_STATIC_PROBE0(sched, remain__cpu);
DT_STATIC_PROBE0(sched, sleep);
+DT_STATIC_PROBE0(sched, stop);
DT_STATIC_PROBE3(sched, steal, "pid_t", "pid_t", "int");
DT_STATIC_PROBE2(sched, unsleep, "pid_t", "pid_t");
DT_STATIC_PROBE3(sched, wakeup, "pid_t", "pid_t", "int");
+DT_STATIC_PROBE3(sched, unstop, "pid_t", "pid_t", "int");
/*
* Raw syscalls
@@ -116,9 +118,11 @@ struct dt_probe *const dtps_static[] = {
&_DT_STATIC_P(sched, on__cpu),
&_DT_STATIC_P(sched, remain__cpu),
&_DT_STATIC_P(sched, sleep),
+ &_DT_STATIC_P(sched, stop),
&_DT_STATIC_P(sched, steal),
&_DT_STATIC_P(sched, unsleep),
&_DT_STATIC_P(sched, wakeup),
+ &_DT_STATIC_P(sched, unstop),
/* Raw syscalls */
&_DT_STATIC_P(raw_syscalls, sys_enter),
&_DT_STATIC_P(raw_syscalls, sys_exit),
Index: dev/pci/drm/drm_linux.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/drm_linux.c,v
diff -u -p -r1.120 drm_linux.c
--- dev/pci/drm/drm_linux.c 7 Feb 2025 03:03:08 -0000 1.120
+++ dev/pci/drm/drm_linux.c 20 Feb 2025 12:33:50 -0000
@@ -122,7 +122,7 @@ __set_current_state(int state)
SCHED_LOCK();
unsleep(p);
p->p_stat = SONPROC;
- atomic_clearbits_int(&p->p_flag, P_WSLEEP);
+ atomic_clearbits_int(&p->p_flag, P_INSCHED);
SCHED_UNLOCK();
}
Index: kern/kern_exit.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exit.c,v
diff -u -p -r1.242 kern_exit.c
--- kern/kern_exit.c 17 Feb 2025 10:16:05 -0000 1.242
+++ kern/kern_exit.c 20 Feb 2025 12:33:52 -0000
@@ -164,13 +164,11 @@ exit1(struct proc *p, int xexit, int xsi
pr->ps_exitcnt++;
/*
- * if somebody else wants to take us to single threaded mode,
- * count ourselves out.
+ * if somebody else wants to take us to single threaded mode
+ * or stop us, count ourselves out.
*/
- if (pr->ps_single) {
- if (--pr->ps_singlecnt == 0)
- wakeup(&pr->ps_singlecnt);
- }
+ if (pr->ps_single != NULL || ISSET(pr->ps_flags, PS_STOPPING))
+ process_suspend_signal(pr);
/* proc is off ps_threads list so update accounting of process now */
tuagg_add_runtime();
@@ -525,7 +523,6 @@ loop:
}
nfound++;
if ((options & WEXITED) && (pr->ps_flags & PS_ZOMBIE)) {
- mtx_leave(&pr->ps_mtx);
*retval = pr->ps_pid;
if (info != NULL) {
info->si_pid = pr->ps_pid;
@@ -548,17 +545,15 @@ loop:
pr->ps_xsig);
if (rusage != NULL)
memcpy(rusage, pr->ps_ru, sizeof(*rusage));
+ mtx_leave(&pr->ps_mtx);
if ((options & WNOWAIT) == 0)
proc_finish_wait(q, pr);
return (0);
}
if ((options & WTRAPPED) && (pr->ps_flags & PS_TRACED) &&
(pr->ps_flags & PS_WAITED) == 0 &&
+ (pr->ps_flags & PS_STOPPED) &&
(pr->ps_flags & PS_TRAPPED)) {
- mtx_leave(&pr->ps_mtx);
- if (single_thread_wait(pr, 0))
- goto loop;
-
if ((options & WNOWAIT) == 0)
atomic_setbits_int(&pr->ps_flags, PS_WAITED);
@@ -573,6 +568,7 @@ loop:
if (statusp != NULL)
*statusp = W_STOPCODE(pr->ps_xsig);
+ mtx_leave(&pr->ps_mtx);
if (rusage != NULL)
memset(rusage, 0, sizeof(*rusage));
return (0);
@@ -581,7 +577,6 @@ loop:
(pr->ps_flags & PS_WAITED) == 0 &&
(pr->ps_flags & PS_STOPPED) &&
(pr->ps_flags & PS_TRAPPED) == 0) {
- mtx_leave(&pr->ps_mtx);
if ((options & WNOWAIT) == 0)
atomic_setbits_int(&pr->ps_flags, PS_WAITED);
@@ -596,12 +591,12 @@ loop:
if (statusp != NULL)
*statusp = W_STOPCODE(pr->ps_xsig);
+ mtx_leave(&pr->ps_mtx);
if (rusage != NULL)
memset(rusage, 0, sizeof(*rusage));
return (0);
}
if ((options & WCONTINUED) && (pr->ps_flags & PS_CONTINUED)) {
- mtx_leave(&pr->ps_mtx);
if ((options & WNOWAIT) == 0)
atomic_clearbits_int(&pr->ps_flags,
PS_CONTINUED);
@@ -615,6 +610,7 @@ loop:
info->si_status = SIGCONT;
}
+ mtx_leave(&pr->ps_mtx);
if (statusp != NULL)
*statusp = _WCONTINUED;
if (rusage != NULL)
Index: kern/kern_fork.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_fork.c,v
diff -u -p -r1.268 kern_fork.c
--- kern/kern_fork.c 10 Nov 2024 06:51:59 -0000 1.268
+++ kern/kern_fork.c 20 Feb 2025 12:33:52 -0000
@@ -590,12 +590,13 @@ thread_fork(struct proc *curp, void *sta
pr->ps_threadcnt++;
/*
- * if somebody else wants to take us to single threaded mode,
- * count ourselves in.
+ * if somebody else wants to take us to single threaded mode
+ * or suspend the process, count ourselves in.
*/
- if (pr->ps_single) {
- pr->ps_singlecnt++;
- atomic_setbits_int(&p->p_flag, P_SUSPSINGLE);
+ if (pr->ps_single != NULL || ISSET(pr->ps_flags, PS_STOPPING)) {
+ pr->ps_suspendcnt++;
+ atomic_setbits_int(&p->p_flag,
+ curp->p_flag & (P_SUSPSINGLE | P_SUSPSIG));
}
mtx_leave(&pr->ps_mtx);
Index: kern/kern_proc.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_proc.c,v
diff -u -p -r1.101 kern_proc.c
--- kern/kern_proc.c 22 Oct 2024 11:54:04 -0000 1.101
+++ kern/kern_proc.c 20 Feb 2025 12:33:52 -0000
@@ -501,7 +501,7 @@ proc_printit(struct proc *p, const char
p->p_runpri, p->p_usrpri, p->p_slppri, p->p_p->ps_nice);
(*pr)(" wchan=%p, wmesg=%s, ps_single=%p scnt=%d ecnt=%d\n",
p->p_wchan, (p->p_wchan && p->p_wmesg) ? p->p_wmesg : "",
- p->p_p->ps_single, p->p_p->ps_singlecnt, p->p_p->ps_exitcnt);
+ p->p_p->ps_single, p->p_p->ps_suspendcnt, p->p_p->ps_exitcnt);
(*pr)(" forw=%p, list=%p,%p\n",
TAILQ_NEXT(p, p_runq), p->p_list.le_next, p->p_list.le_prev);
(*pr)(" process=%p user=%p, vmspace=%p\n",
Index: kern/kern_sched.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sched.c,v
diff -u -p -r1.103 kern_sched.c
--- kern/kern_sched.c 24 Nov 2024 13:05:14 -0000 1.103
+++ kern/kern_sched.c 20 Feb 2025 12:33:52 -0000
@@ -277,7 +277,7 @@ setrunqueue(struct cpu_info *ci, struct
KASSERT(ci != NULL);
SCHED_ASSERT_LOCKED();
KASSERT(p->p_wchan == NULL);
- KASSERT(!ISSET(p->p_flag, P_WSLEEP));
+ KASSERT(!ISSET(p->p_flag, P_INSCHED));
p->p_cpu = ci;
p->p_stat = SRUN;
@@ -368,7 +368,7 @@ again:
}
KASSERT(p->p_wchan == NULL);
- KASSERT(!ISSET(p->p_flag, P_WSLEEP));
+ KASSERT(!ISSET(p->p_flag, P_INSCHED));
return (p);
}
Index: kern/kern_sig.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sig.c,v
diff -u -p -r1.363 kern_sig.c
--- kern/kern_sig.c 17 Feb 2025 15:45:55 -0000 1.363
+++ kern/kern_sig.c 20 Feb 2025 12:33:52 -0000
@@ -61,6 +61,7 @@
#include <sys/pledge.h>
#include <sys/witness.h>
#include <sys/exec_elf.h>
+#include <sys/tracepoint.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
@@ -121,12 +122,10 @@ const int sigprop[NSIG] = {
void setsigvec(struct proc *, int, struct sigaction *);
int proc_trap(struct proc *, int);
-void proc_stop(struct proc *p, int);
-void proc_stop_sweep(void *);
-void *proc_stop_si;
+void proc_stop_setup(struct proc *p);
+void proc_stop_finish(struct proc *p);
void process_continue(struct process *, int);
-void process_stop(struct process *, int, int);
void setsigctx(struct proc *, int, struct sigctx *);
void postsig_done(struct proc *, int, sigset_t, int);
@@ -134,6 +133,7 @@ void postsig(struct proc *, int, struct
int cansignal(struct proc *, struct process *, int);
void ptsignal_locked(struct proc *, int, enum signal_type);
+int proc_suspend_check_locked(struct proc *, int);
struct pool sigacts_pool; /* memory pool for sigacts structures */
@@ -203,11 +203,6 @@ cansignal(struct proc *p, struct process
void
signal_init(void)
{
- proc_stop_si = softintr_establish(IPL_SOFTCLOCK, proc_stop_sweep,
- NULL);
- if (proc_stop_si == NULL)
- panic("signal_init failed to register softintr");
-
pool_init(&sigacts_pool, sizeof(struct sigacts), 0, IPL_NONE,
PR_WAITOK, "sigapl", NULL);
}
@@ -917,7 +912,6 @@ prsignal(struct process *pr, int signum)
/*
* type = SPROCESS process signal, can be diverted (sigwait())
* type = STHREAD thread signal, but should be propagated if unhandled
- * type = SPROPAGATED propagated to this thread, so don't propagate again
*/
void
ptsignal(struct proc *p, int signum, enum signal_type type)
@@ -1009,8 +1003,7 @@ ptsignal_locked(struct proc *p, int sign
}
}
- if (type != SPROPAGATED)
- knote_locked(&pr->ps_klist, NOTE_SIGNAL | signum);
+ knote_locked(&pr->ps_klist, NOTE_SIGNAL | signum);
prop = sigprop[signum];
@@ -1058,20 +1051,11 @@ ptsignal_locked(struct proc *p, int sign
}
/*
* If delivered to process, mark as pending there. Continue and stop
- * signals will be propagated to all threads. So they are always
- * marked at thread level.
+ * signals are always marked at process level.
*/
siglist = (type == SPROCESS) ? &pr->ps_siglist : &p->p_siglist;
if (prop & (SA_CONT | SA_STOP))
- siglist = &p->p_siglist;
-
- /*
- * XXX delay processing of SA_STOP signals unless action == SIG_DFL?
- */
- if (prop & SA_STOP && type != SPROPAGATED)
- TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link)
- if (q != p)
- ptsignal_locked(q, signum, SPROPAGATED);
+ siglist = &pr->ps_siglist;
SCHED_LOCK();
@@ -1222,7 +1206,9 @@ ptsignal_locked(struct proc *p, int sign
goto out;
mask = 0;
pr->ps_xsig = signum;
- proc_stop(p, 0);
+ atomic_setbits_int(&pr->ps_flags, PS_STOPPING);
+ process_stop(pr, P_SUSPSIG, SINGLE_SUSPEND);
+ wakeparent = 1;
goto out;
}
/*
@@ -1270,8 +1256,13 @@ out:
SCHED_UNLOCK();
if (wakeparent) {
- atomic_setbits_int(&pr->ps_pptr->ps_flags, PS_WAITEVENT);
- wakeup(pr->ps_pptr);
+ if (prop & SA_STOP)
+ process_suspend_signal(pr);
+ else {
+ atomic_setbits_int(&pr->ps_pptr->ps_flags,
+ PS_WAITEVENT);
+ wakeup(pr->ps_pptr);
+ }
}
}
@@ -1446,10 +1437,17 @@ cursig(struct proc *p, struct sigctx *sc
* then clear the signal.
*/
if (sctx->sig_stop) {
+ mtx_enter(&pr->ps_mtx);
pr->ps_xsig = signum;
+ atomic_setbits_int(&pr->ps_flags, PS_STOPPING);
SCHED_LOCK();
- proc_stop(p, 1);
+ process_stop(pr, P_SUSPSIG, SINGLE_SUSPEND);
+ atomic_setbits_int(&p->p_flag, P_SUSPSIG);
+ proc_stop_setup(p);
SCHED_UNLOCK();
+ process_suspend_signal(pr);
+ proc_stop_finish(p);
+ mtx_leave(&pr->ps_mtx);
break;
} else if (prop & SA_IGNORE) {
/*
@@ -1499,29 +1497,43 @@ proc_trap(struct proc *p, int signum)
{
struct process *pr = p->p_p;
- single_thread_set(p, SINGLE_SUSPEND | SINGLE_NOWAIT);
-
mtx_enter(&pr->ps_mtx);
+ /*
+ * Wait until any other suspend condition cleared,
+ * including other traps.
+ */
+ proc_suspend_check_locked(p, 0);
+
+ atomic_setbits_int(&pr->ps_flags, PS_STOPPING | PS_TRAPPED);
+ SCHED_LOCK();
+ process_stop(pr, P_SUSPSIG, SINGLE_SUSPEND);
+ atomic_setbits_int(&p->p_flag, P_SUSPSIG);
+ proc_stop_setup(p);
+ SCHED_UNLOCK();
pr->ps_xsig = signum;
pr->ps_trapped = p;
- mtx_leave(&pr->ps_mtx);
- SCHED_LOCK();
- atomic_setbits_int(&pr->ps_flags, PS_TRAPPED);
- proc_stop(p, 1);
+ process_suspend_signal(pr);
+ proc_stop_finish(p);
+ /*
+ * Clear all flags for proc and process by hand here since ptrace
+ * just calls setrunnable on the thread without clearing anything.
+ */
+ atomic_clearbits_int(&p->p_flag, P_SUSPSIG);
atomic_clearbits_int(&pr->ps_flags,
PS_WAITED | PS_STOPPED | PS_TRAPPED);
- SCHED_UNLOCK();
- mtx_enter(&pr->ps_mtx);
signum = pr->ps_xsig;
pr->ps_xsig = 0;
pr->ps_trapped = NULL;
- mtx_leave(&pr->ps_mtx);
- if ((p->p_flag & P_TRACESINGLE) == 0)
- single_thread_clear(p);
+ if ((p->p_flag & P_TRACESINGLE) == 0) {
+ SCHED_LOCK();
+ process_continue(pr, P_SUSPSIG);
+ SCHED_UNLOCK();
+ }
atomic_clearbits_int(&p->p_flag, P_TRACESINGLE);
+ mtx_leave(&pr->ps_mtx);
return signum;
}
@@ -1562,7 +1574,8 @@ process_continue(struct process *pr, int
* Clearing either makes the thread runnable or puts
* it back into some sleep queue.
*/
- if (q->p_stat == SSTOP) {
+ if (q->p_stat == SSTOP &&
+ ISSET(q->p_flag, P_SUSPSIG | P_SUSPSINGLE) == 0) {
if (q->p_wchan == NULL)
setrunnable(q);
else
@@ -1586,10 +1599,10 @@ process_stop(struct process *pr, int fla
/* skip curproc if it is part of pr, caller takes care of that */
if (curproc->p_p == pr) {
p = curproc;
- KASSERT(ISSET(p->p_flag, P_SUSPSINGLE) == 0);
+ KASSERT(ISSET(p->p_flag, P_SUSPSIG | P_SUSPSINGLE) == 0);
}
- pr->ps_singlecnt = pr->ps_threadcnt;
+ pr->ps_suspendcnt = pr->ps_threadcnt;
TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link) {
if (q == p)
continue;
@@ -1608,7 +1621,7 @@ process_stop(struct process *pr, int fla
unsleep(q);
setrunnable(q);
} else
- --pr->ps_singlecnt;
+ --pr->ps_suspendcnt;
break;
case SSLEEP:
/* if it's not interruptible, then just have to wait */
@@ -1616,7 +1629,7 @@ process_stop(struct process *pr, int fla
/* merely need to suspend? just stop it */
if (mode == SINGLE_SUSPEND) {
q->p_stat = SSTOP;
- --pr->ps_singlecnt;
+ --pr->ps_suspendcnt;
} else {
/* need to unwind or exit, so wake it */
unsleep(q);
@@ -1637,56 +1650,77 @@ process_stop(struct process *pr, int fla
}
/*
- * 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.
+ * Prepare a proc to be stopped.
*/
void
-proc_stop(struct proc *p, int sw)
+proc_stop_setup(struct proc *p)
{
- struct process *pr = p->p_p;
-
-#ifdef MULTIPROCESSOR
+ MUTEX_ASSERT_LOCKED(&p->p_p->ps_mtx);
+ /*
+ * XXX in ptsignal the SCHED_LOCK is already held so we can't
+ * grab it here until that is fixed.
+ */
+ /* XXX SCHED_LOCK(); */
SCHED_ASSERT_LOCKED();
-#endif
- /* do not stop exiting procs */
- if (ISSET(p->p_flag, P_WEXIT))
- return;
+ TRACEPOINT(sched, stop, NULL);
+
+ atomic_setbits_int(&p->p_flag, P_INSCHED);
p->p_stat = SSTOP;
- atomic_clearbits_int(&pr->ps_flags, PS_WAITED);
- atomic_setbits_int(&pr->ps_flags, PS_STOPPING);
- atomic_setbits_int(&p->p_flag, P_SUSPSIG);
- /*
- * We need this soft interrupt to be handled fast.
- * Extra calls to softclock don't hurt.
- */
- softintr_schedule(proc_stop_si);
- if (sw)
+ /* XXX SCHED_UNLOCK(); */
+}
+
+/*
+ * Finish stopping a process if the condition still holds.
+ */
+void
+proc_stop_finish(struct proc *p)
+{
+ struct process *pr = p->p_p;
+
+ MUTEX_ASSERT_LOCKED(&pr->ps_mtx);
+ mtx_leave(&pr->ps_mtx);
+ SCHED_LOCK();
+
+ atomic_clearbits_int(&p->p_flag, P_INSCHED);
+ if (p->p_stat == SSTOP) {
+ p->p_ru.ru_nvcsw++;
mi_switch();
+ }
+ KASSERT(p->p_stat == SONPROC);
+
+ SCHED_UNLOCK();
+ mtx_enter(&pr->ps_mtx);
}
/*
- * Called from a soft interrupt to send signals to the parents of stopped
- * processes.
- * We can't do this in proc_stop because it's called with nasty locks held
- * and we would need recursive scheduler lock to deal with that.
+ * Signal either the parent process or the ps_single thread depending on
+ * the mode. Only do this if the suspendcnt dropped to 0. If curproc part
+ * of the process count it out first.
*/
void
-proc_stop_sweep(void *v)
+process_suspend_signal(struct process *pr)
{
- struct process *pr;
+ MUTEX_ASSERT_LOCKED(&pr->ps_mtx);
- LIST_FOREACH(pr, &allprocess, ps_list) {
- if ((pr->ps_flags & PS_STOPPING) == 0)
- continue;
+ /* if part of the process, count us out */
+ if (curproc->p_p == pr)
+ --pr->ps_suspendcnt;
+
+ if (pr->ps_suspendcnt != 0)
+ return;
+
+ if (pr->ps_single == NULL) {
+ atomic_clearbits_int(&pr->ps_flags,
+ PS_STOPPING | PS_WAITED | PS_CONTINUED);
atomic_setbits_int(&pr->ps_flags, PS_STOPPED);
- atomic_clearbits_int(&pr->ps_flags, PS_STOPPING);
if ((pr->ps_pptr->ps_sigacts->ps_sigflags & SAS_NOCLDSTOP) == 0)
prsignal(pr->ps_pptr, SIGCHLD);
atomic_setbits_int(&pr->ps_pptr->ps_flags, PS_WAITEVENT);
wakeup(pr->ps_pptr);
+ } else {
+ wakeup(&pr->ps_suspendcnt);
}
}
@@ -2156,7 +2190,7 @@ userret(struct proc *p)
struct sigctx ctx;
int signum;
- if (p->p_flag & P_SUSPSINGLE)
+ if (atomic_load_int(&p->p_flag) & (P_SUSPSINGLE | P_SUSPSIG))
proc_suspend_check(p, 0);
/* send SIGPROF or SIGVTALRM if their timers interrupted this thread */
@@ -2200,7 +2234,8 @@ proc_suspend_check_locked(struct proc *p
MUTEX_ASSERT_LOCKED(&pr->ps_mtx);
- if (pr->ps_single == NULL || pr->ps_single == p)
+ if ((pr->ps_single == NULL || pr->ps_single == p) &&
+ !ISSET(pr->ps_flags, PS_STOPPING))
return (0);
/* if we're in deep, we need to unwind to the edge */
@@ -2225,18 +2260,14 @@ proc_suspend_check_locked(struct proc *p
/* NOTREACHED */
}
- if (--pr->ps_singlecnt == 0)
- wakeup(&pr->ps_singlecnt);
-
- /* not exiting and don't need to unwind, so suspend */
- mtx_leave(&pr->ps_mtx);
-
SCHED_LOCK();
- p->p_stat = SSTOP;
- mi_switch();
+ proc_stop_setup(p);
SCHED_UNLOCK();
- mtx_enter(&pr->ps_mtx);
- } while (pr->ps_single != NULL);
+ process_suspend_signal(pr);
+
+ /* not exiting and don't need to unwind, so suspend */
+ proc_stop_finish(p);
+ } while (pr->ps_single != NULL || ISSET(pr->ps_flags, PS_STOPPING));
return (0);
}
@@ -2299,37 +2330,15 @@ single_thread_set(struct proc *p, int fl
SCHED_UNLOCK();
/* count ourself out */
- --pr->ps_singlecnt;
- mtx_leave(&pr->ps_mtx);
-
- if ((flags & SINGLE_NOWAIT) == 0)
- single_thread_wait(pr, 1);
+ --pr->ps_suspendcnt;
- return 0;
-}
-
-/*
- * Wait for other threads to stop. If recheck is false then the function
- * returns non-zero if the caller needs to restart the check else 0 is
- * returned. If recheck is true the return value is always 0.
- */
-int
-single_thread_wait(struct process *pr, int recheck)
-{
- int wait;
-
- /* wait until they're all suspended */
- mtx_enter(&pr->ps_mtx);
- while ((wait = pr->ps_singlecnt > 0)) {
- msleep_nsec(&pr->ps_singlecnt, &pr->ps_mtx, PWAIT, "suspend",
+ /* wait until all other threads suspended */
+ while (pr->ps_suspendcnt > 0)
+ msleep_nsec(&pr->ps_suspendcnt, &pr->ps_mtx, PWAIT, "suspend",
INFSLP);
- if (!recheck)
- break;
- }
- KASSERT((pr->ps_single->p_flag & P_SUSPSINGLE) == 0);
mtx_leave(&pr->ps_mtx);
-
- return wait;
+ KASSERT((pr->ps_single->p_flag & P_SUSPSINGLE) == 0);
+ return 0;
}
void
Index: kern/kern_synch.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_synch.c,v
diff -u -p -r1.219 kern_synch.c
--- kern/kern_synch.c 5 Feb 2025 12:21:27 -0000 1.219
+++ kern/kern_synch.c 20 Feb 2025 12:33:52 -0000
@@ -64,8 +64,6 @@
int sleep_signal_check(struct proc *, int);
-extern void proc_stop(struct proc *p, int);
-
/*
* We're only looking at 7 bits of the address; everything is
* aligned to 4, lots of things are aligned to greater powers
@@ -353,7 +351,7 @@ sleep_setup(const volatile void *ident,
p->p_wmesg = wmesg;
p->p_slptime = 0;
p->p_slppri = prio & PRIMASK;
- atomic_setbits_int(&p->p_flag, P_WSLEEP);
+ atomic_setbits_int(&p->p_flag, P_INSCHED);
TAILQ_INSERT_TAIL(&slpque[LOOKUP(ident)], p, p_runq);
if (prio & PCATCH)
atomic_setbits_int(&p->p_flag, P_SINTR);
@@ -399,7 +397,7 @@ sleep_finish(int timo, int do_sleep)
unsleep(p);
if (p->p_stat == SSTOP)
do_sleep = 1;
- atomic_clearbits_int(&p->p_flag, P_WSLEEP);
+ atomic_clearbits_int(&p->p_flag, P_INSCHED);
if (do_sleep) {
KASSERT(p->p_stat == SSLEEP || p->p_stat == SSTOP);
@@ -458,6 +456,7 @@ sleep_finish(int timo, int do_sleep)
int
sleep_signal_check(struct proc *p, int after_sleep)
{
+ struct process *pr = p->p_p;
struct sigctx ctx;
int err, sig;
@@ -467,24 +466,38 @@ sleep_signal_check(struct proc *p, int a
/* requested to stop */
if (!after_sleep) {
- mtx_enter(&p->p_p->ps_mtx);
- if (--p->p_p->ps_singlecnt == 0)
- wakeup(&p->p_p->ps_singlecnt);
- mtx_leave(&p->p_p->ps_mtx);
+ mtx_enter(&pr->ps_mtx);
+ process_suspend_signal(pr);
SCHED_LOCK();
p->p_stat = SSTOP;
SCHED_UNLOCK();
+ mtx_leave(&pr->ps_mtx);
}
}
if ((sig = cursig(p, &ctx, 1)) != 0) {
if (ctx.sig_stop) {
if (!after_sleep) {
- p->p_p->ps_xsig = sig;
+ mtx_enter(&pr->ps_mtx);
+ pr->ps_xsig = sig;
+ /*
+ * This is for stop signals delivered before
+ * sleep_setup() was called. We need to do the
+ * full dance here before going to sleep.
+ */
+ atomic_clearbits_int(&p->p_siglist,
+ sigmask(sig));
+ atomic_setbits_int(&pr->ps_flags, PS_STOPPING);
+ SCHED_LOCK();
+ process_stop(pr, P_SUSPSIG, SINGLE_SUSPEND);
+ SCHED_UNLOCK();
+ atomic_setbits_int(&p->p_flag, P_SUSPSIG);
+ process_suspend_signal(pr);
SCHED_LOCK();
- proc_stop(p, 0);
+ p->p_stat = SSTOP;
SCHED_UNLOCK();
+ mtx_leave(&pr->ps_mtx);
}
} else if (ctx.sig_intr && !ctx.sig_ignore)
return EINTR;
Index: kern/sched_bsd.c
===================================================================
RCS file: /cvs/src/sys/kern/sched_bsd.c,v
diff -u -p -r1.98 sched_bsd.c
--- kern/sched_bsd.c 24 Nov 2024 13:02:37 -0000 1.98
+++ kern/sched_bsd.c 20 Feb 2025 12:33:52 -0000
@@ -465,9 +465,15 @@ setrunnable(struct proc *p)
panic("setrunnable");
case SSTOP:
prio = p->p_usrpri;
- /* if not yet asleep, unstop but don't add to runqueue */
- if (ISSET(p->p_flag, P_WSLEEP)) {
- p->p_stat = SSLEEP;
+ TRACEPOINT(sched, unstop, p->p_tid + THREAD_PID_OFFSET,
+ p->p_p->ps_pid, CPU_INFO_UNIT(p->p_cpu));
+
+ /* If not yet stopped or asleep, unstop but don't add to runq */
+ if (ISSET(p->p_flag, P_INSCHED)) {
+ if (p->p_wchan != NULL)
+ p->p_stat = SSLEEP;
+ else
+ p->p_stat = SONPROC;
return;
}
setrunqueue(NULL, p, prio);
@@ -475,12 +481,12 @@ setrunnable(struct proc *p)
case SSLEEP:
prio = p->p_slppri;
+ TRACEPOINT(sched, wakeup, p->p_tid + THREAD_PID_OFFSET,
+ p->p_p->ps_pid, CPU_INFO_UNIT(p->p_cpu));
/* if not yet asleep, don't add to runqueue */
- if (ISSET(p->p_flag, P_WSLEEP))
+ if (ISSET(p->p_flag, P_INSCHED))
return;
setrunqueue(NULL, p, prio);
- TRACEPOINT(sched, wakeup, p->p_tid + THREAD_PID_OFFSET,
- p->p_p->ps_pid, CPU_INFO_UNIT(p->p_cpu));
break;
}
if (p->p_slptime > 1) {
Index: sys/proc.h
===================================================================
RCS file: /cvs/src/sys/sys/proc.h,v
diff -u -p -r1.382 proc.h
--- sys/proc.h 17 Feb 2025 15:45:55 -0000 1.382
+++ sys/proc.h 20 Feb 2025 12:33:52 -0000
@@ -191,7 +191,7 @@ struct process {
struct proc *ps_single; /* [m] Thread for single-threading. */
struct proc *ps_trapped; /* [m] Thread trapped for ptrace. */
- u_int ps_singlecnt; /* [m] Number of threads to suspend. */
+ u_int ps_suspendcnt; /* [m] Number of threads to suspend. */
u_int ps_exitcnt; /* [m] Number of threads in exit1. */
int ps_traceflag; /* Kernel trace points. */
@@ -437,7 +437,7 @@ struct proc {
#define P_ALRMPEND 0x00000004 /* SIGVTALRM needs to be posted */
#define P_SIGSUSPEND 0x00000008 /* Need to restore before-suspend mask*/
#define P_CANTSLEEP 0x00000010 /* insomniac thread */
-#define P_WSLEEP 0x00000020 /* Working on going to sleep. */
+#define P_INSCHED 0x00000020 /* Switching scheduler state. */
#define P_SINTR 0x00000080 /* Sleep is interruptible. */
#define P_SYSTEM 0x00000200 /* No sigs, stats or swapping. */
#define P_TIMEOUT 0x00000400 /* Timing out during sleep. */
@@ -451,7 +451,7 @@ struct proc {
#define P_BITS \
("\20" "\01INKTR" "\02PROFPEND" "\03ALRMPEND" "\04SIGSUSPEND" \
- "\05CANTSLEEP" "\06WSLEEP" "\010SINTR" "\012SYSTEM" "\013TIMEOUT" \
+ "\05CANTSLEEP" "\06INSCHED" "\010SINTR" "\012SYSTEM" "\013TIMEOUT" \
"\015TRACESINGLE" "\016WEXIT" "\020OWEUPC" "\024SUSPSINGLE" \
"\033THREAD" "\034SUSPSIG" "\037CPUPEG")
@@ -599,13 +599,13 @@ refreshcreds(struct proc *p)
#define SINGLE_MASK 0x0f
/* extra flags for single_thread_set */
#define SINGLE_DEEP 0x10 /* call is in deep */
-#define SINGLE_NOWAIT 0x20 /* do not wait for other threads to stop */
int single_thread_set(struct proc *, int);
-int single_thread_wait(struct process *, int);
void single_thread_clear(struct proc *);
int proc_suspend_check(struct proc *, int);
+void process_suspend_signal(struct process *);
+void process_stop(struct process *, int, int);
void child_return(void *);
Index: sys/signalvar.h
===================================================================
RCS file: /cvs/src/sys/sys/signalvar.h,v
diff -u -p -r1.57 signalvar.h
--- sys/signalvar.h 4 Nov 2024 22:41:50 -0000 1.57
+++ sys/signalvar.h 20 Feb 2025 12:33:52 -0000
@@ -89,7 +89,7 @@ struct sigacts {
#define sigcantmask (sigmask(SIGKILL) | sigmask(SIGSTOP))
#ifdef _KERNEL
-enum signal_type { SPROCESS, STHREAD, SPROPAGATED };
+enum signal_type { SPROCESS, STHREAD };
struct sigio_ref;
fix stop signal delivery