Module Name:    src
Committed By:   riastradh
Date:           Mon Jul 17 10:55:27 UTC 2023

Modified Files:
        src/sys/kern: kern_kthread.c

Log Message:
kthread(9): Fix nested kthread_join.

No reason for one kthread_join to interfere with another, or to cause
non-cyclic dependencies to get stuck.

Uses struct lwp::l_private for this purpose, which for user threads
stores the tls pointer.  I don't think anything in kthread(9) uses
l_private -- generally kernel threads will use lwp specificdata.  But
maybe this should use a new member instead, or a union member with an
existing pointer for the purpose.


To generate a diff of this commit:
cvs rdiff -u -r1.47 -r1.48 src/sys/kern/kern_kthread.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_kthread.c
diff -u src/sys/kern/kern_kthread.c:1.47 src/sys/kern/kern_kthread.c:1.48
--- src/sys/kern/kern_kthread.c:1.47	Tue Sep 13 09:37:49 2022
+++ src/sys/kern/kern_kthread.c	Mon Jul 17 10:55:27 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_kthread.c,v 1.47 2022/09/13 09:37:49 riastradh Exp $	*/
+/*	$NetBSD: kern_kthread.c,v 1.48 2023/07/17 10:55:27 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2007, 2009, 2019 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_kthread.c,v 1.47 2022/09/13 09:37:49 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_kthread.c,v 1.48 2023/07/17 10:55:27 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/cpu.h>
@@ -45,7 +45,6 @@ __KERNEL_RCSID(0, "$NetBSD: kern_kthread
 
 #include <uvm/uvm_extern.h>
 
-static lwp_t *		kthread_jtarget;
 static kmutex_t		kthread_lock;
 static kcondvar_t	kthread_cv;
 
@@ -55,7 +54,6 @@ kthread_sysinit(void)
 
 	mutex_init(&kthread_lock, MUTEX_DEFAULT, IPL_NONE);
 	cv_init(&kthread_cv, "kthrwait");
-	kthread_jtarget = NULL;
 }
 
 /*
@@ -172,11 +170,14 @@ kthread_exit(int ecode)
 
 	/* Barrier for joining. */
 	if (l->l_pflag & LP_MUSTJOIN) {
+		bool *exitedp;
+
 		mutex_enter(&kthread_lock);
-		while (kthread_jtarget != l) {
+		while ((exitedp = l->l_private) == NULL) {
 			cv_wait(&kthread_cv, &kthread_lock);
 		}
-		kthread_jtarget = NULL;
+		KASSERT(!*exitedp);
+		*exitedp = true;
 		cv_broadcast(&kthread_cv);
 		mutex_exit(&kthread_lock);
 	}
@@ -197,22 +198,21 @@ kthread_exit(int ecode)
 int
 kthread_join(lwp_t *l)
 {
+	bool exited = false;
 
 	KASSERT((l->l_flag & LW_SYSTEM) != 0);
 	KASSERT((l->l_pflag & LP_MUSTJOIN) != 0);
 
 	/*
-	 * - Wait if some other thread has occupied the target.
-	 * - Specify our kthread as a target and notify it.
-	 * - Wait for the target kthread to notify us.
+	 * - Ask the kthread to write to `exited'.
+	 * - After this, touching l is forbidden -- it may be freed.
+	 * - Wait until the kthread has written to `exited'.
 	 */
 	mutex_enter(&kthread_lock);
-	while (kthread_jtarget) {
-		cv_wait(&kthread_cv, &kthread_lock);
-	}
-	kthread_jtarget = l;
+	KASSERT(l->l_private == NULL);
+	l->l_private = &exited;
 	cv_broadcast(&kthread_cv);
-	while (kthread_jtarget == l) {
+	while (!exited) {
 		cv_wait(&kthread_cv, &kthread_lock);
 	}
 	mutex_exit(&kthread_lock);

Reply via email to