Module Name:    src
Committed By:   rmind
Date:           Thu May 19 03:07:30 UTC 2011

Modified Files:
        src/share/man/man9: kthread.9
        src/sys/kern: init_main.c kern_kthread.c
        src/sys/sys: kthread.h lwp.h

Log Message:
Re-implement kthread_join(9), so that it actually works (hi haad@).


To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 src/share/man/man9/kthread.9
cvs rdiff -u -r1.428 -r1.429 src/sys/kern/init_main.c
cvs rdiff -u -r1.32 -r1.33 src/sys/kern/kern_kthread.c
cvs rdiff -u -r1.9 -r1.10 src/sys/sys/kthread.h
cvs rdiff -u -r1.151 -r1.152 src/sys/sys/lwp.h

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

Modified files:

Index: src/share/man/man9/kthread.9
diff -u src/share/man/man9/kthread.9:1.24 src/share/man/man9/kthread.9:1.25
--- src/share/man/man9/kthread.9:1.24	Thu Dec  2 12:54:13 2010
+++ src/share/man/man9/kthread.9	Thu May 19 03:07:30 2011
@@ -1,4 +1,4 @@
-.\"     $NetBSD: kthread.9,v 1.24 2010/12/02 12:54:13 wiz Exp $
+.\"     $NetBSD: kthread.9,v 1.25 2011/05/19 03:07:30 rmind Exp $
 .\"
 .\" Copyright (c) 2000, 2007, 2008 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd May 13, 2010
+.Dd May 19, 2011
 .Dt KTHREAD 9
 .Os
 .Sh NAME
@@ -89,16 +89,13 @@
 .Dv NULL
 if not required.
 .It Fa newlp
-A pointer to receive the new lwp structure for the kernel thread.
-May not be
-.Dv NULL
-if
+A pointer to receive the new LWP structure for the kernel thread.
+May be
+.Dv NULL ,
+unless
 .Dv KTHREAD_JOINABLE
 is specified in
-.Fa flags ;
-otherwise may be
-.Dv NULL
-if not required.
+.Fa flags .
 .It Fa fmt
 A string containing format information used to display the kernel
 thread name.
@@ -129,7 +126,7 @@
 Causes the kthread to be created in the
 .Dv SCHED_OTHER
 class (timeshared).
-The threads' priority will be dynamically adjusted by the scheduler.
+The priority of thread will be dynamically adjusted by the scheduler.
 Increased activity by the kthread will cause its priority to fall;
 decreased activity will cause its priority to rise.
 By default, kthreads are created in the
@@ -143,10 +140,11 @@
 adjusted by the scheduler.
 .It Dv KTHREAD_JOINABLE
 Requests creation of joinable kthread.
-When this flag is specified, the
+In such case
+.Fn kthread_exit
+will wait until
 .Fn kthread_join
-function can be called only once for the lwp structure returned in
-.Fa newlp .
+will be called.
 .El
 .It Fn kthread_destroy "l"
 From another thread executing in the kernel, cause a kthread to exit.
@@ -157,9 +155,13 @@
 Exit from a kernel thread.
 Must only be called by a kernel thread.
 .It Fn kthread_join "l"
-Suspend execution of the LWP until the target kthread terminates.
+Suspend execution of calling thread until the target kthread terminates.
 Conceptually the function can be compared to the user space
-.Xr pthread_join 3 .
+.Xr pthread_join 3 ,
+however it must be called only once for kernel thread which was created using
+.Dv KTHREAD_JOIN
+flag and would wait on
+.Fa kthread_exit .
 .El
 .Sh RETURN VALUES
 Upon successful completion,

Index: src/sys/kern/init_main.c
diff -u src/sys/kern/init_main.c:1.428 src/sys/kern/init_main.c:1.429
--- src/sys/kern/init_main.c:1.428	Thu Apr 14 16:20:52 2011
+++ src/sys/kern/init_main.c	Thu May 19 03:07:29 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: init_main.c,v 1.428 2011/04/14 16:20:52 yamt Exp $	*/
+/*	$NetBSD: init_main.c,v 1.429 2011/05/19 03:07:29 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -97,7 +97,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.428 2011/04/14 16:20:52 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.429 2011/05/19 03:07:29 rmind Exp $");
 
 #include "opt_ddb.h"
 #include "opt_ipsec.h"
@@ -304,6 +304,7 @@
 	once_init();
 	mutex_init(&cpu_lock, MUTEX_DEFAULT, IPL_NONE);
 	kernconfig_lock_init();
+	kthread_sysinit();
 
 	/* Initialize the device switch tables. */
 	devsw_init();

Index: src/sys/kern/kern_kthread.c
diff -u src/sys/kern/kern_kthread.c:1.32 src/sys/kern/kern_kthread.c:1.33
--- src/sys/kern/kern_kthread.c:1.32	Tue Apr 26 17:40:38 2011
+++ src/sys/kern/kern_kthread.c	Thu May 19 03:07:29 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_kthread.c,v 1.32 2011/04/26 17:40:38 ahoka Exp $	*/
+/*	$NetBSD: kern_kthread.c,v 1.33 2011/05/19 03:07:29 rmind Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2007, 2009 The NetBSD Foundation, Inc.
@@ -31,45 +31,45 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_kthread.c,v 1.32 2011/04/26 17:40:38 ahoka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_kthread.c,v 1.33 2011/05/19 03:07:29 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/kthread.h>
-#include <sys/proc.h>
+#include <sys/mutex.h>
 #include <sys/sched.h>
 #include <sys/kmem.h>
 
 #include <uvm/uvm_extern.h>
-
-/*
- * note that stdarg.h and the ansi style va_start macro is used for both
- * ansi and traditional c complers.
- * XXX: this requires that stdarg.h define: va_alist and va_dcl
- */
 #include <machine/stdarg.h>
 
+static lwp_t *		kthread_jtarget;
+static kmutex_t		kthread_lock;
+static kcondvar_t	kthread_cv;
+
+void
+kthread_sysinit(void)
+{
+
+	mutex_init(&kthread_lock, MUTEX_DEFAULT, IPL_NONE);
+	cv_init(&kthread_cv, "kthrwait");
+	kthread_jtarget = NULL;
+}
+
 /*
- * Fork a kernel thread.  Any process can request this to be done.
- *
- * With joinable kthreads KTHREAD_JOINABLE flag this should be known.
- * 1. If you specify KTHREAD_JOINABLE, you must call kthread_join() to reap
- *    the thread. It will not be automatically reaped by the system.
- * 2. For any given call to kthread_create(KTHREAD_JOINABLE), you may call
- *    kthread_join() only once on the returned lwp_t *.
+ * kthread_create: create a kernel thread, that is, system-only LWP.
  */
 int
 kthread_create(pri_t pri, int flag, struct cpu_info *ci,
-	       void (*func)(void *), void *arg,
-	       lwp_t **lp, const char *fmt, ...)
+    void (*func)(void *), void *arg, lwp_t **lp, const char *fmt, ...)
 {
 	lwp_t *l;
 	vaddr_t uaddr;
-	int error, lc, lwp_flags;
+	int error, lc;
 	va_list ap;
 
-	lwp_flags = LWP_DETACHED;
+	KASSERT((flag & KTHREAD_INTR) == 0 || (flag & KTHREAD_MPSAFE) != 0);
 
 	uaddr = uvm_uarea_system_alloc();
 	if (uaddr == 0) {
@@ -81,11 +81,7 @@
 		lc = SCHED_RR;
 	}
 
-	if ((flag & KTHREAD_JOINABLE) != 0) {
-		lwp_flags &= ~LWP_DETACHED;
-	}
-
-	error = lwp_create(&lwp0, &proc0, uaddr, lwp_flags, NULL,
+	error = lwp_create(&lwp0, &proc0, uaddr, LWP_DETACHED, NULL,
 	    0, func, arg, &l, lc);
 	if (error) {
 		uvm_uarea_system_free(uaddr);
@@ -105,15 +101,6 @@
 	/*
 	 * Set parameters.
 	 */
-	if ((flag & KTHREAD_INTR) != 0) {
-		KASSERT((flag & KTHREAD_MPSAFE) != 0);
-	}
-
-	/* Joinable kthread can't be NULL. */
-	if ((flag & KTHREAD_JOINABLE) != 0) {
-		KASSERT(l != NULL);
-	}
-	
 	if (pri == PRI_NONE) {
 		if ((flag & KTHREAD_TS) != 0) {
 			/* Maximum user priority level. */
@@ -134,10 +121,17 @@
 		l->l_pflag |= LP_BOUND;
 		l->l_cpu = ci;
 	}
-	if ((flag & KTHREAD_INTR) != 0)
+
+	if ((flag & KTHREAD_JOINABLE) != 0) {
+		KASSERT(lp != NULL);
+		l->l_pflag |= LP_JOINABLE;
+	}
+	if ((flag & KTHREAD_INTR) != 0) {
 		l->l_pflag |= LP_INTR;
-	if ((flag & KTHREAD_MPSAFE) == 0)
+	}
+	if ((flag & KTHREAD_MPSAFE) == 0) {
 		l->l_pflag &= ~LP_MPSAFE;
+	}
 
 	/*
 	 * Set the new LWP running, unless the caller has requested
@@ -152,10 +146,10 @@
 	mutex_exit(proc0.p_lock);
 
 	/* All done! */
-	if (lp != NULL)
+	if (lp != NULL) {
 		*lp = l;
-
-	return (0);
+	}
+	return 0;
 }
 
 /*
@@ -176,15 +170,20 @@
 		    name, l->l_lid, ecode);
 	}
 
+	/* Barrier for joining. */
+	if (l->l_pflag & LP_JOINABLE) {
+		mutex_enter(&kthread_lock);
+		while (kthread_jtarget != l) {
+			cv_wait(&kthread_cv, &kthread_lock);
+		}
+		kthread_jtarget = NULL;
+		cv_broadcast(&kthread_cv);
+		mutex_exit(&kthread_lock);
+	}
+
 	/* And exit.. */
 	lwp_exit(l);
-
-	/*
-	 * XXX Fool the compiler.  Making exit1() __noreturn__ is a can
-	 * XXX of worms right now.
-	 */
-	for (;;)
-		;
+	KASSERT(false);
 }
 
 /*
@@ -193,18 +192,10 @@
 void
 kthread_destroy(lwp_t *l)
 {
-	proc_t *p;
-	
+
 	KASSERT((l->l_flag & LW_SYSTEM) != 0);
 	KASSERT(l->l_stat == LSIDL);
 
-	p = l->l_proc;
-	
-	/* Add LRP_DETACHED flag because we can have joinable kthread now. */
-	mutex_enter(p->p_lock);
-	l->l_prflag |= LPR_DETACHED;
-	mutex_exit(p->p_lock);
-	
 	lwp_exit(l);
 }
 
@@ -214,18 +205,24 @@
 int
 kthread_join(lwp_t *l)
 {
-	lwpid_t departed;
-	proc_t *p;
-	int error;
 
 	KASSERT((l->l_flag & LW_SYSTEM) != 0);
-	KASSERT((l->l_prflag & LPR_DETACHED) == 0);
-	
-	p = curlwp->l_proc;
-
-	mutex_enter(p->p_lock);
-	error = lwp_wait1(curlwp, l->l_lid, &departed, LWPWAIT_EXITCONTROL);
-	mutex_exit(p->p_lock);
 
-	return error;
+	/*
+	 * - Wait if some other thread has occupied the target.
+	 * - Speicfy our kthread as a target and notify it.
+	 * - Wait for the target kthread to notify us.
+	 */
+	mutex_enter(&kthread_lock);
+	while (kthread_jtarget) {
+		cv_wait(&kthread_cv, &kthread_lock);
+	}
+	kthread_jtarget = l;
+	cv_broadcast(&kthread_cv);
+	while (kthread_jtarget == l) {
+		cv_wait(&kthread_cv, &kthread_lock);
+	}
+	mutex_exit(&kthread_lock);
+
+	return 0;
 }

Index: src/sys/sys/kthread.h
diff -u src/sys/sys/kthread.h:1.9 src/sys/sys/kthread.h:1.10
--- src/sys/sys/kthread.h:1.9	Tue May 11 22:26:00 2010
+++ src/sys/sys/kthread.h	Thu May 19 03:07:29 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: kthread.h,v 1.9 2010/05/11 22:26:00 haad Exp $	*/
+/*	$NetBSD: kthread.h,v 1.10 2011/05/19 03:07:29 rmind Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2007, 2009 The NetBSD Foundation, Inc.
@@ -33,18 +33,23 @@
 #ifndef _SYS_KTHREAD_H_
 #define	_SYS_KTHREAD_H_
 
+#if !defined(_KERNEL)
+#error "not supposed to be exposed to userland"
+#endif
+
 /*
  * Kernel thread handling.
  */
 
-#ifdef _KERNEL
 #include <sys/proc.h>
 
-#define	KTHREAD_IDLE	0x01	/* do not set runnable */
-#define	KTHREAD_MPSAFE	0x02	/* does not need kernel_lock */
-#define	KTHREAD_INTR	0x04	/* interrupt handler */
-#define	KTHREAD_TS	0x08	/* timeshared */
-#define	KTHREAD_JOINABLE	0x10	/* joinable thread */
+#define	KTHREAD_IDLE		0x01	/* Do not run on creation */
+#define	KTHREAD_MPSAFE		0x02	/* Do not acquire kernel_lock */
+#define	KTHREAD_INTR		0x04	/* Software interrupt handler */
+#define	KTHREAD_TS		0x08	/* Time-sharing priority range */
+#define	KTHREAD_JOINABLE	0x10	/* Joinable */
+
+void	kthread_sysinit(void);
 
 int	kthread_create(pri_t, int, struct cpu_info *,
 		       void (*)(void *), void *,
@@ -53,6 +58,5 @@
 void	kthread_exit(int) __dead;
 void	kthread_destroy(lwp_t *);
 int	kthread_join(lwp_t *);
-#endif /* _KERNEL */
 
 #endif /* _SYS_KTHREAD_H_ */

Index: src/sys/sys/lwp.h
diff -u src/sys/sys/lwp.h:1.151 src/sys/sys/lwp.h:1.152
--- src/sys/sys/lwp.h:1.151	Mon May  2 02:28:57 2011
+++ src/sys/sys/lwp.h	Thu May 19 03:07:29 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: lwp.h,v 1.151 2011/05/02 02:28:57 rmind Exp $	*/
+/*	$NetBSD: lwp.h,v 1.152 2011/05/19 03:07:29 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010
@@ -247,6 +247,7 @@
 #define	LP_MPSAFE	0x00000020 /* Starts life without kernel_lock */
 #define	LP_INTR		0x00000040 /* Soft interrupt handler */
 #define	LP_SYSCTLWRITE	0x00000080 /* sysctl write lock held */
+#define	LP_JOINABLE	0x00000100 /* Joinable kthread */
 #define	LP_SA_PAGEFAULT	0x00000200 /* SA LWP in pagefault handler */
 #define	LP_SA_NOBLOCK	0x00000400 /* SA don't upcall on block */
 #define	LP_TIMEINTR	0x00010000 /* Time this soft interrupt */

Reply via email to