Module Name:    src
Committed By:   pooka
Date:           Wed Jan 12 12:51:21 UTC 2011

Modified Files:
        src/sys/rump/librump/rumpkern: locks.c lwproc.c rump.c sleepq.c

Log Message:
When the client and the rump kernel are the same host process, all
threads blocking in the kernel automatically exit when the process
exists.  However, for the sysproxy case this does not hold.
Typically it's ~harmless, but e.g. in the case of socket binding
following by poll it gets annoying.

Introduce sysproxy procexit, which wakes up all threads blocking
on a condition when a process's communication socket is closed.
The code is a little different from the regular kernel simply
because in a rump kernel l_mutex is not available at all times
(this is because scheduling happens on every kernel entry and exit,
and that path must be kept lockless for any reasonable performance).
Instead, use gating which makes sure all threads are either out of
the cv code or suspended in a well-known state.  Then, wake up the
threads and tell them to get the hell out of our galaxy.


To generate a diff of this commit:
cvs rdiff -u -r1.46 -r1.47 src/sys/rump/librump/rumpkern/locks.c
cvs rdiff -u -r1.8 -r1.9 src/sys/rump/librump/rumpkern/lwproc.c
cvs rdiff -u -r1.218 -r1.219 src/sys/rump/librump/rumpkern/rump.c
cvs rdiff -u -r1.10 -r1.11 src/sys/rump/librump/rumpkern/sleepq.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/rump/librump/rumpkern/locks.c
diff -u src/sys/rump/librump/rumpkern/locks.c:1.46 src/sys/rump/librump/rumpkern/locks.c:1.47
--- src/sys/rump/librump/rumpkern/locks.c:1.46	Thu Jan  6 13:36:48 2011
+++ src/sys/rump/librump/rumpkern/locks.c	Wed Jan 12 12:51:21 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: locks.c,v 1.46 2011/01/06 13:36:48 pooka Exp $	*/
+/*	$NetBSD: locks.c,v 1.47 2011/01/12 12:51:21 pooka Exp $	*/
 
 /*
  * Copyright (c) 2007, 2008 Antti Kantee.  All Rights Reserved.
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: locks.c,v 1.46 2011/01/06 13:36:48 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: locks.c,v 1.47 2011/01/12 12:51:21 pooka Exp $");
 
 #include <sys/param.h>
 #include <sys/kmem.h>
@@ -262,15 +262,70 @@
 	rumpuser_cv_destroy(RUMPCV(cv));
 }
 
+static int
+docvwait(kcondvar_t *cv, kmutex_t *mtx, struct timespec *ts)
+{
+	struct lwp *l = curlwp;
+	int rv;
+
+	if (__predict_false(l->l_stat == LSDEAD || l->l_stat == LSZOMB)) {
+		/*
+		 * sleepq code expects us to sleep, so set l_mutex
+		 * back to cpu lock here if we didn't.
+		 */
+		l->l_mutex = l->l_cpu->ci_schedstate.spc_mutex;
+		return EINTR;
+	}
+
+	UNLOCKED(mtx, false);
+
+	l->l_private = cv;
+	rv = 0;
+	if (ts) {
+		if (rumpuser_cv_timedwait(RUMPCV(cv), RUMPMTX(mtx),
+		    ts->tv_sec, ts->tv_nsec))
+			rv = EWOULDBLOCK;
+	} else {
+		rumpuser_cv_wait(RUMPCV(cv), RUMPMTX(mtx));
+	}
+
+	/*
+	 * Check for LSDEAD.  if so, we need to wait here until we
+	 * are allowed to exit.
+	 */
+	if (__predict_false(l->l_stat == LSDEAD)) {
+		struct proc *p = l->l_proc;
+
+		mutex_exit(mtx); /* drop and retake later */
+
+		mutex_enter(p->p_lock);
+		while (l->l_stat == LSDEAD) {
+			/* avoid recursion */
+			rumpuser_cv_wait(RUMPCV(&p->p_waitcv),
+			    RUMPMTX(p->p_lock));
+		}
+		KASSERT(l->l_stat == LSZOMB);
+		mutex_exit(p->p_lock);
+
+		/* ok, we can exit and remove "reference" to l->private */
+
+		mutex_enter(mtx);
+		rv = EINTR;
+	}
+	l->l_private = NULL;
+
+	LOCKED(mtx, false);
+
+	return rv;
+}
+
 void
 cv_wait(kcondvar_t *cv, kmutex_t *mtx)
 {
 
 	if (__predict_false(rump_threads == 0))
 		panic("cv_wait without threads");
-	UNLOCKED(mtx, false);
-	rumpuser_cv_wait(RUMPCV(cv), RUMPMTX(mtx));
-	LOCKED(mtx, false);
+	(void) docvwait(cv, mtx, NULL);
 }
 
 int
@@ -279,10 +334,7 @@
 
 	if (__predict_false(rump_threads == 0))
 		panic("cv_wait without threads");
-	UNLOCKED(mtx, false);
-	rumpuser_cv_wait(RUMPCV(cv), RUMPMTX(mtx));
-	LOCKED(mtx, false);
-	return 0;
+	return docvwait(cv, mtx, NULL);
 }
 
 int
@@ -293,8 +345,7 @@
 	int rv;
 
 	if (ticks == 0) {
-		cv_wait(cv, mtx);
-		rv = 0;
+		rv = cv_wait_sig(cv, mtx);
 	} else {
 		/*
 		 * XXX: this fetches rump kernel time, but
@@ -305,13 +356,7 @@
 		tick.tv_nsec = (ticks % hz) * (1000000000/hz);
 		timespecadd(&ts, &tick, &ts);
 
-		UNLOCKED(mtx, false);
-		if (rumpuser_cv_timedwait(RUMPCV(cv), RUMPMTX(mtx),
-		    ts.tv_sec, ts.tv_nsec))
-			rv = EWOULDBLOCK;
-		else
-			rv = 0;
-		LOCKED(mtx, false);
+		rv = docvwait(cv, mtx, &ts);
 	}
 
 	return rv;

Index: src/sys/rump/librump/rumpkern/lwproc.c
diff -u src/sys/rump/librump/rumpkern/lwproc.c:1.8 src/sys/rump/librump/rumpkern/lwproc.c:1.9
--- src/sys/rump/librump/rumpkern/lwproc.c:1.8	Thu Jan  6 11:22:55 2011
+++ src/sys/rump/librump/rumpkern/lwproc.c	Wed Jan 12 12:51:21 2011
@@ -1,4 +1,4 @@
-/*      $NetBSD: lwproc.c,v 1.8 2011/01/06 11:22:55 pooka Exp $	*/
+/*      $NetBSD: lwproc.c,v 1.9 2011/01/12 12:51:21 pooka Exp $	*/
 
 /*
  * Copyright (c) 2010, 2011 Antti Kantee.  All Rights Reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lwproc.c,v 1.8 2011/01/06 11:22:55 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lwproc.c,v 1.9 2011/01/12 12:51:21 pooka Exp $");
 
 #include <sys/param.h>
 #include <sys/atomic.h>
@@ -218,6 +218,7 @@
 	l->l_fd = p->p_fd;
 	l->l_cpu = NULL;
 	l->l_target_cpu = rump_cpu; /* Initial target CPU always the same */
+	l->l_stat = LSRUN;
 	TAILQ_INIT(&l->l_ld_locks);
 
 	lwp_initspecific(l);

Index: src/sys/rump/librump/rumpkern/rump.c
diff -u src/sys/rump/librump/rumpkern/rump.c:1.218 src/sys/rump/librump/rumpkern/rump.c:1.219
--- src/sys/rump/librump/rumpkern/rump.c:1.218	Fri Jan  7 15:10:22 2011
+++ src/sys/rump/librump/rumpkern/rump.c	Wed Jan 12 12:51:21 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: rump.c,v 1.218 2011/01/07 15:10:22 pooka Exp $	*/
+/*	$NetBSD: rump.c,v 1.219 2011/01/12 12:51:21 pooka Exp $	*/
 
 /*
  * Copyright (c) 2007 Antti Kantee.  All Rights Reserved.
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.218 2011/01/07 15:10:22 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.219 2011/01/12 12:51:21 pooka Exp $");
 
 #include <sys/systm.h>
 #define ELFSIZE ARCH_ELFSIZE
@@ -101,6 +101,7 @@
 
 static int rump_proxy_syscall(int, void *, register_t *);
 static int rump_proxy_rfork(void *, int);
+static void rump_proxy_procexit(void);
 
 static char rump_msgbuf[16*1024]; /* 16k should be enough for std rump needs */
 
@@ -210,6 +211,7 @@
 	.spop_lwproc_rfork	= rump_proxy_rfork,
 	.spop_lwproc_newlwp	= rump_lwproc_newlwp,
 	.spop_lwproc_curlwp	= rump_lwproc_curlwp,
+	.spop_procexit		= rump_proxy_procexit,
 	.spop_syscall		= rump_proxy_syscall,
 	.spop_getpid		= spgetpid,
 };
@@ -735,6 +737,61 @@
 	return 0;
 }
 
+static void
+rump_proxy_procexit(void)
+{
+	struct proc *p = curproc;
+	uint64_t where;
+	struct lwp *l;
+
+	mutex_enter(p->p_lock);
+	/*
+	 * First pass: mark all lwps in the process with LSDEAD
+	 * so that they know they should exit.
+	 */
+	LIST_FOREACH(l, &p->p_lwps, l_sibling) {
+		if (l == curlwp)
+			continue;
+		l->l_stat = LSDEAD;
+	}
+	mutex_exit(p->p_lock);
+
+	/*
+	 * Next, make sure everyone on all CPUs sees our status
+	 * update.  This keeps threads inside cv_wait() and makes
+	 * sure we don't access a stale cv pointer later when
+	 * we wake up the threads.
+	 */
+
+	where = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
+	xc_wait(where);
+
+	/*
+	 * Ok, all lwps are either:
+	 *  1) not in the cv code
+	 *  2) sleeping on l->l_private
+	 *  3) sleeping on p->p_waitcv
+	 *
+	 * Either way, l_private is stable until we change the lwps
+	 * state to LSZOMB.
+	 */
+
+	mutex_enter(p->p_lock);
+	LIST_FOREACH(l, &p->p_lwps, l_sibling) {
+		if (l->l_private)
+			cv_broadcast(l->l_private);
+		l->l_stat = LSZOMB;
+	}
+	cv_broadcast(&p->p_waitcv);
+	mutex_exit(p->p_lock);
+
+	/*
+	 * Don't wait for lwps to exit.  There's refcounting in the
+	 * rumpuser sp code which makes this safe.  Also, this routine
+	 * should sleep for a long time.
+	 */
+}
+
 int
 rump_boot_gethowto()
 {

Index: src/sys/rump/librump/rumpkern/sleepq.c
diff -u src/sys/rump/librump/rumpkern/sleepq.c:1.10 src/sys/rump/librump/rumpkern/sleepq.c:1.11
--- src/sys/rump/librump/rumpkern/sleepq.c:1.10	Sat Dec 18 14:01:43 2010
+++ src/sys/rump/librump/rumpkern/sleepq.c	Wed Jan 12 12:51:21 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: sleepq.c,v 1.10 2010/12/18 14:01:43 skrll Exp $	*/
+/*	$NetBSD: sleepq.c,v 1.11 2011/01/12 12:51:21 pooka Exp $	*/
 
 /*
  * Copyright (c) 2008 Antti Kantee.  All Rights Reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sleepq.c,v 1.10 2010/12/18 14:01:43 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sleepq.c,v 1.11 2011/01/12 12:51:21 pooka Exp $");
 
 #include <sys/param.h>
 #include <sys/condvar.h>
@@ -87,7 +87,8 @@
 
 	while (l->l_wchan) {
 		l->l_mutex = mp;
-		if ((error=cv_timedwait(&sq_cv, mp, timo)) == EWOULDBLOCK) {
+		error = cv_timedwait(&sq_cv, mp, timo);
+		if (error == EWOULDBLOCK || error == EINTR) {
 			TAILQ_REMOVE(l->l_sleepq, l, l_sleepchain);
 			l->l_wchan = NULL;
 		}

Reply via email to