git: d7a9e6e74067 - main - thread_single: wait for P_STOPPED_SINGLE to pass

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 13 Jun 2022 19:33:30 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=d7a9e6e74067f70eeec74dcd64a9bcc851503a6e

commit d7a9e6e74067f70eeec74dcd64a9bcc851503a6e
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2022-05-03 19:48:50 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-06-13 19:30:02 +0000

    thread_single: wait for P_STOPPED_SINGLE to pass
    
    to avoid ALLPROC mode to try to race with any other single-threading
    mode.
    
    In collaboration with:  pho
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      2 weeks
    Differential revision:  https://reviews.freebsd.org/D35310
---
 sys/kern/kern_thread.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
index 57d235c002f0..4dd8dbdfb5a7 100644
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -1207,10 +1207,18 @@ thread_single(struct proc *p, int mode)
 	mtx_assert(&Giant, MA_NOTOWNED);
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 
-	if ((p->p_flag & P_HADTHREADS) == 0 && mode != SINGLE_ALLPROC)
+	/*
+	 * Is someone already single threading?
+	 * Or may be singlethreading is not needed at all.
+	 */
+	if (mode == SINGLE_ALLPROC) {
+		while ((p->p_flag & P_STOPPED_SINGLE) != 0) {
+			if ((p->p_flag2 & P2_WEXIT) != 0)
+				return (1);
+			msleep(&p->p_flag, &p->p_mtx, PCATCH, "thrsgl", 0);
+		}
+	} else if ((p->p_flag & P_HADTHREADS) == 0)
 		return (0);
-
-	/* Is someone already single threading? */
 	if (p->p_singlethread != NULL && p->p_singlethread != td)
 		return (1);
 
@@ -1669,6 +1677,7 @@ thread_single_end(struct proc *p, int mode)
 	PROC_SUNLOCK(p);
 	if (wakeup_swapper)
 		kick_proc0();
+	wakeup(&p->p_flag);
 }
 
 /*