single_thread_clear() manipulates the same data structures as single_thread_set() and, as such, doesn't need the KERNEL_LOCK().
However cursig() does need some sort of serialization to ensure that per-process data structures like signals, flags and traced-signum stay consistent. So the diff below move the assertion up in preparation for more mp work. ok? Index: kern/kern_sig.c =================================================================== RCS file: /cvs/src/sys/kern/kern_sig.c,v retrieving revision 1.274 diff -u -p -r1.274 kern_sig.c --- kern/kern_sig.c 4 Mar 2021 09:02:37 -0000 1.274 +++ kern/kern_sig.c 4 Mar 2021 09:35:47 -0000 @@ -1182,6 +1182,8 @@ cursig(struct proc *p) int dolock = (p->p_flag & P_SINTR) == 0; int s; + KERNEL_ASSERT_LOCKED(); + sigpending = (p->p_siglist | pr->ps_siglist); if (sigpending == 0) return 0; @@ -1225,11 +1227,7 @@ cursig(struct proc *p) if (dolock) SCHED_UNLOCK(s); - if (dolock) - KERNEL_LOCK(); single_thread_clear(p, 0); - if (dolock) - KERNEL_UNLOCK(); /* * If we are no longer being traced, or the parent @@ -2128,7 +2126,6 @@ single_thread_clear(struct proc *p, int KASSERT(pr->ps_single == p); KASSERT(curproc == p); - KERNEL_ASSERT_LOCKED(); SCHED_LOCK(s); pr->ps_single = NULL;