Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/rump/librump/rumpkern When the client and the rump kerne...



details:   https://anonhg.NetBSD.org/src/rev/9e928ddf3893
branches:  trunk
changeset: 760734:9e928ddf3893
user:      pooka <pooka%NetBSD.org@localhost>
date:      Wed Jan 12 12:51:21 2011 +0000

description:
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.

diffstat:

 sys/rump/librump/rumpkern/locks.c  |  81 +++++++++++++++++++++++++++++--------
 sys/rump/librump/rumpkern/lwproc.c |   5 +-
 sys/rump/librump/rumpkern/rump.c   |  61 +++++++++++++++++++++++++++-
 sys/rump/librump/rumpkern/sleepq.c |   7 +-
 4 files changed, 129 insertions(+), 25 deletions(-)

diffs (279 lines):

diff -r 7742a0e9f1a5 -r 9e928ddf3893 sys/rump/librump/rumpkern/locks.c
--- a/sys/rump/librump/rumpkern/locks.c Wed Jan 12 12:32:53 2011 +0000
+++ b/sys/rump/librump/rumpkern/locks.c Wed Jan 12 12:51:21 2011 +0000
@@ -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;
diff -r 7742a0e9f1a5 -r 9e928ddf3893 sys/rump/librump/rumpkern/lwproc.c
--- a/sys/rump/librump/rumpkern/lwproc.c        Wed Jan 12 12:32:53 2011 +0000
+++ b/sys/rump/librump/rumpkern/lwproc.c        Wed Jan 12 12:51:21 2011 +0000
@@ -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);
diff -r 7742a0e9f1a5 -r 9e928ddf3893 sys/rump/librump/rumpkern/rump.c
--- a/sys/rump/librump/rumpkern/rump.c  Wed Jan 12 12:32:53 2011 +0000
+++ b/sys/rump/librump/rumpkern/rump.c  Wed Jan 12 12:51:21 2011 +0000
@@ -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()
 {
diff -r 7742a0e9f1a5 -r 9e928ddf3893 sys/rump/librump/rumpkern/sleepq.c
--- a/sys/rump/librump/rumpkern/sleepq.c        Wed Jan 12 12:32:53 2011 +0000
+++ b/sys/rump/librump/rumpkern/sleepq.c        Wed Jan 12 12:51:21 2011 +0000
@@ -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;
                }



Home | Main Index | Thread Index | Old Index