Module Name: src Committed By: pooka Date: Wed Sep 1 19:37:59 UTC 2010
Modified Files: src/sys/rump/librump/rumpkern: Makefile.rumpkern emul.c rump.c rump_private.h scheduler.c sysproxy_socket.c threads.c src/sys/sys: lwp.h Added Files: src/sys/rump/librump/rumpkern: lwproc.c Log Message: Implement rump_lwproc: the new lwp/proc management routines for rump. These move the management of the pid/lwpid space from the application into the kernel, make code more robust, and make it possible to attach multiple lwp's to non-proc0 processes. To generate a diff of this commit: cvs rdiff -u -r1.95 -r1.96 src/sys/rump/librump/rumpkern/Makefile.rumpkern cvs rdiff -u -r1.144 -r1.145 src/sys/rump/librump/rumpkern/emul.c cvs rdiff -u -r0 -r1.1 src/sys/rump/librump/rumpkern/lwproc.c cvs rdiff -u -r1.183 -r1.184 src/sys/rump/librump/rumpkern/rump.c cvs rdiff -u -r1.54 -r1.55 src/sys/rump/librump/rumpkern/rump_private.h cvs rdiff -u -r1.18 -r1.19 src/sys/rump/librump/rumpkern/scheduler.c cvs rdiff -u -r1.7 -r1.8 src/sys/rump/librump/rumpkern/sysproxy_socket.c cvs rdiff -u -r1.11 -r1.12 src/sys/rump/librump/rumpkern/threads.c cvs rdiff -u -r1.137 -r1.138 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/sys/rump/librump/rumpkern/Makefile.rumpkern diff -u src/sys/rump/librump/rumpkern/Makefile.rumpkern:1.95 src/sys/rump/librump/rumpkern/Makefile.rumpkern:1.96 --- src/sys/rump/librump/rumpkern/Makefile.rumpkern:1.95 Mon Aug 30 09:44:40 2010 +++ src/sys/rump/librump/rumpkern/Makefile.rumpkern Wed Sep 1 19:37:58 2010 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.rumpkern,v 1.95 2010/08/30 09:44:40 pooka Exp $ +# $NetBSD: Makefile.rumpkern,v 1.96 2010/09/01 19:37:58 pooka Exp $ # .include "${RUMPTOP}/Makefile.rump" @@ -15,9 +15,9 @@ # # Source modules, first the ones specifically implemented for librump. # -SRCS= rump.c rumpcopy.c emul.c intr.c klock.c kobj_rename.c \ - ltsleep.c memalloc.c scheduler.c signals.c sleepq.c \ - sysproxy_socket.c threads.c vm.c +SRCS= rump.c rumpcopy.c emul.c intr.c lwproc.c klock.c \ + kobj_rename.c ltsleep.c memalloc.c scheduler.c \ + signals.c sleepq.c sysproxy_socket.c threads.c vm.c SRCS+= compat.c # Multiprocessor or uniprocessor locking. TODO: select right Index: src/sys/rump/librump/rumpkern/emul.c diff -u src/sys/rump/librump/rumpkern/emul.c:1.144 src/sys/rump/librump/rumpkern/emul.c:1.145 --- src/sys/rump/librump/rumpkern/emul.c:1.144 Wed Jun 23 08:36:03 2010 +++ src/sys/rump/librump/rumpkern/emul.c Wed Sep 1 19:37:58 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: emul.c,v 1.144 2010/06/23 08:36:03 pooka Exp $ */ +/* $NetBSD: emul.c,v 1.145 2010/09/01 19:37:58 pooka Exp $ */ /* * Copyright (c) 2007 Antti Kantee. All Rights Reserved. @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: emul.c,v 1.144 2010/06/23 08:36:03 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: emul.c,v 1.145 2010/09/01 19:37:58 pooka Exp $"); #include <sys/param.h> #include <sys/null.h> @@ -158,6 +158,25 @@ (*l->l_syncobj->sobj_unsleep)(l, cleanup); } +void +lwp_update_creds(struct lwp *l) +{ + struct proc *p; + kauth_cred_t oldcred; + + p = l->l_proc; + oldcred = l->l_cred; + l->l_prflag &= ~LPR_CRMOD; + + mutex_enter(p->p_lock); + kauth_cred_hold(p->p_cred); + l->l_cred = p->p_cred; + mutex_exit(p->p_lock); + + if (oldcred != NULL) + kauth_cred_free(oldcred); +} + vaddr_t calc_cache_size(struct vm_map *map, int pct, int va_pct) { Index: src/sys/rump/librump/rumpkern/rump.c diff -u src/sys/rump/librump/rumpkern/rump.c:1.183 src/sys/rump/librump/rumpkern/rump.c:1.184 --- src/sys/rump/librump/rumpkern/rump.c:1.183 Mon Aug 30 10:49:40 2010 +++ src/sys/rump/librump/rumpkern/rump.c Wed Sep 1 19:37:58 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: rump.c,v 1.183 2010/08/30 10:49:40 pooka Exp $ */ +/* $NetBSD: rump.c,v 1.184 2010/09/01 19:37:58 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.183 2010/08/30 10:49:40 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.184 2010/09/01 19:37:58 pooka Exp $"); #include <sys/systm.h> #define ELFSIZE ARCH_ELFSIZE @@ -303,11 +303,12 @@ kauth_init(); rump_susercred = rump_cred_create(0, 0, 0, NULL); - l->l_cred = rump_cred_suserget(); - l->l_proc = &proc0; - procinit(); proc0_init(); + + l->l_proc = &proc0; + lwp_update_creds(l); + lwpinit_specificdata(); lwp_initspecific(&lwp0); @@ -483,138 +484,6 @@ return resid; } -static pid_t nextpid = 1; -struct lwp * -rump_newproc_switch() -{ - struct lwp *l; - pid_t mypid; - - mypid = atomic_inc_uint_nv(&nextpid); - if (__predict_false(mypid == 0)) - mypid = atomic_inc_uint_nv(&nextpid); - - l = rump_lwp_alloc(mypid, 0); - rump_lwp_switch(l); - - return l; -} - -struct lwp * -rump_lwp_alloc_and_switch(pid_t pid, lwpid_t lid) -{ - struct lwp *l; - - l = rump_lwp_alloc(pid, lid); - rump_lwp_switch(l); - - return l; -} - -struct lwp * -rump_lwp_alloc(pid_t pid, lwpid_t lid) -{ - struct lwp *l; - struct proc *p; - - l = kmem_zalloc(sizeof(*l), KM_SLEEP); - if (pid != 0) { - p = kmem_zalloc(sizeof(*p), KM_SLEEP); - if (rump_proc_vfs_init) - rump_proc_vfs_init(p); - p->p_stats = proc0.p_stats; /* XXX */ - p->p_limit = lim_copy(proc0.p_limit); - p->p_pid = pid; - p->p_vmspace = &vmspace0; - p->p_emul = &emul_netbsd; - p->p_fd = fd_init(NULL); - p->p_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); - p->p_pgrp = &rump_pgrp; - p->p_cred = l->l_cred = rump_cred_suserget(); - - chgproccnt(0, 1); - atomic_inc_uint(&nprocs); - } else { - p = &proc0; - l->l_cred = rump_susercred; - } - - l->l_proc = p; - l->l_lid = lid; - l->l_fd = p->p_fd; - if (pid == 0) - fd_hold(l); - l->l_cpu = NULL; - l->l_target_cpu = rump_cpu; - lwp_initspecific(l); - LIST_INSERT_HEAD(&alllwp, l, l_list); - - return l; -} - -void -rump_lwp_switch(struct lwp *newlwp) -{ - struct lwp *l = curlwp; - - rumpuser_set_curlwp(NULL); - newlwp->l_cpu = newlwp->l_target_cpu = l->l_cpu; - newlwp->l_mutex = l->l_mutex; - l->l_mutex = NULL; - l->l_cpu = NULL; - rumpuser_set_curlwp(newlwp); - if (l->l_flag & LW_WEXIT) - rump_lwp_free(l); -} - -/* XXX: this has effect only on non-pid0 lwps */ -void -rump_lwp_release(struct lwp *l) -{ - struct proc *p; - - p = l->l_proc; - if (p->p_pid != 0) { - mutex_obj_free(p->p_lock); - fd_free(); - chgproccnt(kauth_cred_getuid(p->p_cred), -1); - if (rump_proc_vfs_release) - rump_proc_vfs_release(p); - rump_cred_put(l->l_cred); - limfree(p->p_limit); - kmem_free(p, sizeof(*p)); - - atomic_dec_uint(&nprocs); - } else { - fd_free(); - } - KASSERT((l->l_flag & LW_WEXIT) == 0); - l->l_flag |= LW_WEXIT; -} - -void -rump_lwp_free(struct lwp *l) -{ - - KASSERT(l->l_flag & LW_WEXIT); - KASSERT(l->l_mutex == NULL); - if (l->l_name) - kmem_free(l->l_name, MAXCOMLEN); - lwp_finispecific(l); - LIST_REMOVE(l, l_list); - kmem_free(l, sizeof(*l)); -} - -struct lwp * -rump_lwp_curlwp(void) -{ - struct lwp *l = curlwp; - - if (l->l_flag & LW_WEXIT) - return NULL; - return l; -} - /* rump private. NEEDS WORK! */ void rump_set_vmspace(struct vmspace *vm) @@ -652,36 +521,6 @@ kauth_cred_free(cred); } -kauth_cred_t -rump_cred_suserget(void) -{ - - kauth_cred_hold(rump_susercred); - return rump_susercred; -} - -/* - * Return the next system lwpid - */ -lwpid_t -rump_nextlid(void) -{ - lwpid_t retid; - - mutex_enter(proc0.p_lock); - /* - * Take next one, don't return 0 - * XXX: most likely we'll have collisions in case this - * wraps around. - */ - if (++proc0.p_nlwpid == 0) - ++proc0.p_nlwpid; - retid = proc0.p_nlwpid; - mutex_exit(proc0.p_lock); - - return retid; -} - static int compcounter[RUMP_COMPONENT_MAX]; static void @@ -840,3 +679,18 @@ rumpuser_dprintf("%s / %s: %" PRIu64 "\n", ev->ev_group, ev->ev_name, ev->ev_count); } + +/* + * If you use this interface ... well ... all bets are off. + * The original purpose is for the p2k fs server library to be + * able to use the same pid/lid for VOPs as the host kernel. + */ +void +rump_allbetsareoff_setid(pid_t pid, int lid) +{ + struct lwp *l = curlwp; + struct proc *p = l->l_proc; + + l->l_lid = lid; + p->p_pid = pid; +} Index: src/sys/rump/librump/rumpkern/rump_private.h diff -u src/sys/rump/librump/rumpkern/rump_private.h:1.54 src/sys/rump/librump/rumpkern/rump_private.h:1.55 --- src/sys/rump/librump/rumpkern/rump_private.h:1.54 Mon Jun 14 21:04:56 2010 +++ src/sys/rump/librump/rumpkern/rump_private.h Wed Sep 1 19:37:58 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: rump_private.h,v 1.54 2010/06/14 21:04:56 pooka Exp $ */ +/* $NetBSD: rump_private.h,v 1.55 2010/09/01 19:37:58 pooka Exp $ */ /* * Copyright (c) 2007 Antti Kantee. All Rights Reserved. @@ -93,8 +93,6 @@ void rump_gettime(struct timespec *); void rump_getuptime(struct timespec *); -void rump_lwp_free(struct lwp *); -lwpid_t rump_nextlid(void); void rump_set_vmspace(struct vmspace *); typedef void (*rump_proc_vfs_init_fn)(struct proc *); @@ -110,6 +108,8 @@ int rump_sysproxy_copyout(const void *, void *, size_t); int rump_sysproxy_copyin(const void *, void *, size_t); +struct lwp * rump__lwproc_allockernlwp(void); + void rump_cpus_bootstrap(int); void rump_scheduler_init(void); void rump_schedule(void); Index: src/sys/rump/librump/rumpkern/scheduler.c diff -u src/sys/rump/librump/rumpkern/scheduler.c:1.18 src/sys/rump/librump/rumpkern/scheduler.c:1.19 --- src/sys/rump/librump/rumpkern/scheduler.c:1.18 Sun Aug 15 20:23:04 2010 +++ src/sys/rump/librump/rumpkern/scheduler.c Wed Sep 1 19:37:59 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: scheduler.c,v 1.18 2010/08/15 20:23:04 pooka Exp $ */ +/* $NetBSD: scheduler.c,v 1.19 2010/09/01 19:37:59 pooka Exp $ */ /* * Copyright (c) 2010 Antti Kantee. All Rights Reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: scheduler.c,v 1.18 2010/08/15 20:23:04 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: scheduler.c,v 1.19 2010/09/01 19:37:59 pooka Exp $"); #include <sys/param.h> #include <sys/atomic.h> @@ -78,7 +78,7 @@ static struct rumpuser_cv *lwp0cv; static unsigned nextcpu; -static bool lwp0busy = false; +static bool lwp0isbusy = false; /* * Keep some stats. @@ -187,6 +187,30 @@ ts->tv_sec, ts->tv_nsec); } +static void +lwp0busy(void) +{ + + /* busy lwp0 */ + KASSERT(curlwp == NULL || curlwp->l_cpu == NULL); + rumpuser_mutex_enter_nowrap(lwp0mtx); + while (lwp0isbusy) + rumpuser_cv_wait_nowrap(lwp0cv, lwp0mtx); + lwp0isbusy = true; + rumpuser_mutex_exit(lwp0mtx); +} + +static void +lwp0rele(void) +{ + + rumpuser_mutex_enter_nowrap(lwp0mtx); + KASSERT(lwp0isbusy == true); + lwp0isbusy = false; + rumpuser_cv_signal(lwp0cv); + rumpuser_mutex_exit(lwp0mtx); +} + void rump_schedule() { @@ -199,31 +223,27 @@ * for this case -- anyone who cares about performance will * start a real thread. */ - l = rumpuser_get_curlwp(); - if (l == NULL) { - /* busy lwp0 */ - rumpuser_mutex_enter_nowrap(lwp0mtx); - while (lwp0busy) - rumpuser_cv_wait_nowrap(lwp0cv, lwp0mtx); - lwp0busy = true; - rumpuser_mutex_exit(lwp0mtx); + if (__predict_true((l = rumpuser_get_curlwp()) != NULL)) { + rump_schedule_cpu(l); + LWP_CACHE_CREDS(l, l->l_proc); + } else { + lwp0busy(); /* schedule cpu and use lwp0 */ rump_schedule_cpu(&lwp0); rumpuser_set_curlwp(&lwp0); - l = rump_lwp_alloc(0, rump_nextlid()); - /* release lwp0 */ - rump_lwp_switch(l); - rumpuser_mutex_enter_nowrap(lwp0mtx); - lwp0busy = false; - rumpuser_cv_signal(lwp0cv); - rumpuser_mutex_exit(lwp0mtx); + /* allocate thread, switch to it, and release lwp0 */ + l = rump__lwproc_allockernlwp(); + rump_lwproc_switch(l); + lwp0rele(); - /* mark new lwp as dead-on-exit */ - rump_lwp_release(l); - } else { - rump_schedule_cpu(l); + /* + * mark new thread dead-on-unschedule. this + * means that we'll be running with l_refcnt == 0. + * relax, it's fine. + */ + rump_lwproc_releaselwp(); } } @@ -331,29 +351,31 @@ l->l_mutex = NULL; /* - * If we're using a temp lwp, need to take lwp0 for rump_lwp_free(). - * (we could maybe cache idle lwp's to avoid constant bouncing) + * Check special conditions: + * 1) do we need to free the lwp which just unscheduled? + * (locking order: lwp0, cpu) + * 2) do we want to clear curlwp for the current host thread */ - if (l->l_flag & LW_WEXIT) { - rumpuser_set_curlwp(NULL); + if (__predict_false(l->l_flag & LW_WEXIT)) { + lwp0busy(); - /* busy lwp0 */ - rumpuser_mutex_enter_nowrap(lwp0mtx); - while (lwp0busy) - rumpuser_cv_wait_nowrap(lwp0cv, lwp0mtx); - lwp0busy = true; - rumpuser_mutex_exit(lwp0mtx); + /* Now that we have lwp0, we can schedule a CPU again */ + rump_schedule_cpu(l); - rump_schedule_cpu(&lwp0); - rumpuser_set_curlwp(&lwp0); - rump_lwp_free(l); + /* switch to lwp0. this frees the old thread */ + KASSERT(l->l_flag & LW_WEXIT); + rump_lwproc_switch(&lwp0); + + /* release lwp0 */ rump_unschedule_cpu(&lwp0); + lwp0.l_mutex = NULL; + lwp0.l_pflag &= ~LP_RUNNING; + lwp0rele(); rumpuser_set_curlwp(NULL); - rumpuser_mutex_enter_nowrap(lwp0mtx); - lwp0busy = false; - rumpuser_cv_signal(lwp0cv); - rumpuser_mutex_exit(lwp0mtx); + } else if (__predict_false(l->l_flag & LW_RUMP_CLEAR)) { + rumpuser_set_curlwp(NULL); + l->l_flag &= ~LW_RUMP_CLEAR; } } Index: src/sys/rump/librump/rumpkern/sysproxy_socket.c diff -u src/sys/rump/librump/rumpkern/sysproxy_socket.c:1.7 src/sys/rump/librump/rumpkern/sysproxy_socket.c:1.8 --- src/sys/rump/librump/rumpkern/sysproxy_socket.c:1.7 Wed Aug 11 11:51:06 2010 +++ src/sys/rump/librump/rumpkern/sysproxy_socket.c Wed Sep 1 19:37:59 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: sysproxy_socket.c,v 1.7 2010/08/11 11:51:06 pgoyette Exp $ */ +/* $NetBSD: sysproxy_socket.c,v 1.8 2010/09/01 19:37:59 pooka Exp $ */ /* * Copyright (c) 2009 Antti Kantee. All Rights Reserved. @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sysproxy_socket.c,v 1.7 2010/08/11 11:51:06 pgoyette Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sysproxy_socket.c,v 1.8 2010/09/01 19:37:59 pooka Exp $"); #include <sys/param.h> #include <sys/kernel.h> @@ -388,14 +388,14 @@ callp = rump_sysent + req->rpc_sysnum; mylwp = curlwp; - l = rump_newproc_switch(); + rump_lwproc_newproc(); rump_set_vmspace(&rump_sysproxy_vmspace); resp.rpc_retval = 0; /* default */ resp.rpc_error = callp->sy_call(l, (void *)req->rpc_data, &resp.rpc_retval); - rump_lwp_release(l); - rump_lwp_switch(mylwp); + rump_lwproc_releaselwp(); + rump_lwproc_switch(mylwp); kmem_free(req, req->rpc_head.rpch_flen); dosend(sock, qent, (uint8_t *)&resp, sizeof(resp), false); Index: src/sys/rump/librump/rumpkern/threads.c diff -u src/sys/rump/librump/rumpkern/threads.c:1.11 src/sys/rump/librump/rumpkern/threads.c:1.12 --- src/sys/rump/librump/rumpkern/threads.c:1.11 Thu Jun 3 19:36:21 2010 +++ src/sys/rump/librump/rumpkern/threads.c Wed Sep 1 19:37:59 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: threads.c,v 1.11 2010/06/03 19:36:21 pooka Exp $ */ +/* $NetBSD: threads.c,v 1.12 2010/09/01 19:37:59 pooka Exp $ */ /* * Copyright (c) 2007-2009 Antti Kantee. All Rights Reserved. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: threads.c,v 1.11 2010/06/03 19:36:21 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: threads.c,v 1.12 2010/09/01 19:37:59 pooka Exp $"); #include <sys/param.h> #include <sys/atomic.h> @@ -139,7 +139,7 @@ k = malloc(sizeof(*k), M_TEMP, M_WAITOK); k->f = func; k->arg = arg; - k->mylwp = l = rump_lwp_alloc(0, rump_nextlid()); + k->mylwp = l = rump__lwproc_allockernlwp(); l->l_flag |= LW_SYSTEM; if (flags & KTHREAD_MPSAFE) l->l_pflag |= LP_MPSAFE; @@ -174,7 +174,7 @@ if ((curlwp->l_pflag & LP_MPSAFE) == 0) KERNEL_UNLOCK_LAST(NULL); - rump_lwp_release(curlwp); + rump_lwproc_releaselwp(); /* unschedule includes membar */ rump_unschedule(); rumpuser_thread_exit(); Index: src/sys/sys/lwp.h diff -u src/sys/sys/lwp.h:1.137 src/sys/sys/lwp.h:1.138 --- src/sys/sys/lwp.h:1.137 Thu Jul 8 12:23:31 2010 +++ src/sys/sys/lwp.h Wed Sep 1 19:37:58 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: lwp.h,v 1.137 2010/07/08 12:23:31 rmind Exp $ */ +/* $NetBSD: lwp.h,v 1.138 2010/09/01 19:37:58 pooka Exp $ */ /*- * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010 @@ -240,6 +240,7 @@ #define LW_UNPARKED 0x10000000 /* Unpark op pending */ #define LW_SA_YIELD 0x40000000 /* LWP on VP is yielding */ #define LW_SA_IDLE 0x80000000 /* VP is idle */ +#define LW_RUMP_CLEAR LW_SA_IDLE /* clear curlwp in rump scheduler */ /* The second set of flags is kept in l_pflag. */ #define LP_KTRACTIVE 0x00000001 /* Executing ktrace operation */ Added files: Index: src/sys/rump/librump/rumpkern/lwproc.c diff -u /dev/null src/sys/rump/librump/rumpkern/lwproc.c:1.1 --- /dev/null Wed Sep 1 19:37:59 2010 +++ src/sys/rump/librump/rumpkern/lwproc.c Wed Sep 1 19:37:58 2010 @@ -0,0 +1,339 @@ +/* $NetBSD: lwproc.c,v 1.1 2010/09/01 19:37:58 pooka Exp $ */ + +/* + * Copyright (c) 2010 Antti Kantee. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: lwproc.c,v 1.1 2010/09/01 19:37:58 pooka Exp $"); + +#include <sys/param.h> +#include <sys/atomic.h> +#include <sys/filedesc.h> +#include <sys/kauth.h> +#include <sys/kmem.h> +#include <sys/lwp.h> +#include <sys/pool.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/resourcevar.h> +#include <sys/uidinfo.h> + +#include <rump/rumpuser.h> + +#include "rump_private.h" + +static void +lwproc_proc_free(struct proc *p) +{ + kauth_cred_t cred; + + mutex_enter(proc_lock); + + KASSERT(p->p_nlwps == 0); + KASSERT(LIST_EMPTY(&p->p_lwps)); + KASSERT(p->p_stat == SIDL || p->p_stat == SDEAD); + + LIST_REMOVE(p, p_list); + LIST_REMOVE(p, p_sibling); + proc_free_pid(p->p_pid); /* decrements nprocs */ + proc_leavepgrp(p); /* releases proc_lock */ + + cred = p->p_cred; + chgproccnt(kauth_cred_getuid(cred), -1); + if (rump_proc_vfs_release) + rump_proc_vfs_release(p); + + limfree(p->p_limit); + pstatsfree(p->p_stats); + kauth_cred_free(p->p_cred); + proc_finispecific(p); + + mutex_obj_free(p->p_lock); + mutex_destroy(&p->p_stmutex); + mutex_destroy(&p->p_auxlock); + rw_destroy(&p->p_reflock); + cv_destroy(&p->p_waitcv); + cv_destroy(&p->p_lwpcv); + + proc_free_mem(p); +} + +/* + * Allocate a new process. Mostly mimic fork by + * copying the properties of the parent. However, there are some + * differences. For example, we never share the fd table. + * + * Switch to the new lwp and return a pointer to it. + */ +static struct proc * +lwproc_newproc(struct proc *parent) +{ + uid_t uid = kauth_cred_getuid(parent->p_cred); + struct proc *p; + + /* maxproc not enforced */ + atomic_inc_uint(&nprocs); + + /* allocate process */ + p = proc_alloc(); + memset(&p->p_startzero, 0, + offsetof(struct proc, p_endzero) + - offsetof(struct proc, p_startzero)); + memcpy(&p->p_startcopy, &parent->p_startcopy, + offsetof(struct proc, p_endcopy) + - offsetof(struct proc, p_startcopy)); + + p->p_stats = pstatscopy(parent->p_stats); + + /* not based on parent */ + p->p_vmspace = &vmspace0; + p->p_emul = &emul_netbsd; + p->p_fd = fd_init(NULL); + lim_addref(parent->p_limit); + p->p_limit = parent->p_limit; + + LIST_INIT(&p->p_lwps); + LIST_INIT(&p->p_children); + + p->p_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); + mutex_init(&p->p_stmutex, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&p->p_auxlock, MUTEX_DEFAULT, IPL_NONE); + rw_init(&p->p_reflock); + cv_init(&p->p_waitcv, "pwait"); + cv_init(&p->p_lwpcv, "plwp"); + + p->p_pptr = parent; + p->p_ppid = parent->p_pid; + + kauth_proc_fork(parent, p); + + /* initialize cwd in rump kernels with vfs */ + if (rump_proc_vfs_init) + rump_proc_vfs_init(p); + + chgproccnt(uid, 1); /* not enforced */ + + /* publish proc various proc lists */ + mutex_enter(proc_lock); + LIST_INSERT_HEAD(&allproc, p, p_list); + LIST_INSERT_HEAD(&parent->p_children, p, p_sibling); + LIST_INSERT_AFTER(parent, p, p_pglist); + mutex_exit(proc_lock); + + return p; +} + +static void +lwproc_freelwp(struct lwp *l) +{ + struct proc *p; + bool freeproc; + + p = l->l_proc; + mutex_enter(p->p_lock); + + /* XXX: l_refcnt */ + KASSERT(l->l_flag & LW_WEXIT); + KASSERT(l->l_refcnt == 0); + + /* ok, zero references, continue with nuke */ + LIST_REMOVE(l, l_sibling); + KASSERT(p->p_nlwps >= 1); + if (--p->p_nlwps == 0) { + KASSERT(p != &proc0); + p->p_stat = SDEAD; + } + freeproc = p->p_nlwps == 0; + cv_broadcast(&p->p_lwpcv); /* nobody sleeps on this in rump? */ + kauth_cred_free(l->l_cred); + mutex_exit(p->p_lock); + + mutex_enter(proc_lock); + LIST_REMOVE(l, l_list); + mutex_exit(proc_lock); + + if (l->l_name) + kmem_free(l->l_name, MAXCOMLEN); + lwp_finispecific(l); + + kmem_free(l, sizeof(*l)); + + if (p->p_stat == SDEAD) + lwproc_proc_free(p); +} + +/* + * called with p_lock held, releases lock before return + */ +static void +lwproc_makelwp(struct proc *p, struct lwp *l, bool doswitch, bool procmake) +{ + + p->p_nlwps++; + l->l_refcnt = 1; + l->l_proc = p; + + l->l_lid = p->p_nlwpid++; + LIST_INSERT_HEAD(&p->p_lwps, l, l_sibling); + mutex_exit(p->p_lock); + + lwp_update_creds(l); + + l->l_fd = p->p_fd; + l->l_cpu = NULL; + l->l_target_cpu = rump_cpu; /* Initial target CPU always the same */ + + lwp_initspecific(l); + + if (doswitch) { + rump_lwproc_switch(l); + } + + /* filedesc already has refcount 1 when process is created */ + if (!procmake) { + fd_hold(l); + } + + mutex_enter(proc_lock); + LIST_INSERT_HEAD(&alllwp, l, l_list); + mutex_exit(proc_lock); +} + +struct lwp * +rump__lwproc_allockernlwp(void) +{ + struct proc *p; + struct lwp *l; + + l = kmem_zalloc(sizeof(*l), KM_SLEEP); + + p = &proc0; + mutex_enter(p->p_lock); + lwproc_makelwp(p, l, false, false); + + return l; +} + +int +rump_lwproc_newlwp(pid_t pid) +{ + struct proc *p; + struct lwp *l; + + l = kmem_zalloc(sizeof(*l), KM_SLEEP); + mutex_enter(proc_lock); + p = proc_find_raw(pid); + if (p == NULL) { + mutex_exit(proc_lock); + kmem_free(l, sizeof(*l)); + return ESRCH; + } + mutex_enter(p->p_lock); + mutex_exit(proc_lock); + lwproc_makelwp(p, l, true, false); + + return 0; +} + +int +rump_lwproc_newproc(void) +{ + struct proc *p; + struct lwp *l; + + p = lwproc_newproc(curproc); + l = kmem_zalloc(sizeof(*l), KM_SLEEP); + mutex_enter(p->p_lock); + lwproc_makelwp(p, l, true, true); + + return 0; +} + +/* + * Switch to a new process/thread. Release previous one if + * deemed to be exiting. + */ +void +rump_lwproc_switch(struct lwp *newlwp) +{ + struct lwp *l = curlwp; + + KASSERT(!(l->l_flag & LW_WEXIT) || newlwp); + + if (__predict_false(newlwp && (newlwp->l_pflag & LP_RUNNING))) + panic("lwp %p (%d:%d) already running", + newlwp, newlwp->l_proc->p_pid, newlwp->l_lid); + + if (newlwp == NULL) { + l->l_pflag &= ~LP_RUNNING; + l->l_flag |= LW_RUMP_CLEAR; + return; + } + + /* fd_free() must be called from curlwp context. talk about ugh */ + if (l->l_flag & LW_WEXIT) { + fd_free(); + } + + rumpuser_set_curlwp(NULL); + + newlwp->l_cpu = newlwp->l_target_cpu = l->l_cpu; + newlwp->l_mutex = l->l_mutex; + newlwp->l_pflag |= LP_RUNNING; + + rumpuser_set_curlwp(newlwp); + + l->l_mutex = NULL; + l->l_cpu = NULL; + l->l_pflag &= ~LP_RUNNING; + + if (l->l_flag & LW_WEXIT) { + lwproc_freelwp(l); + } +} + +void +rump_lwproc_releaselwp(void) +{ + struct proc *p; + struct lwp *l = curlwp; + + p = l->l_proc; + mutex_enter(p->p_lock); + KASSERT(l->l_refcnt != 0); + l->l_refcnt--; + mutex_exit(p->p_lock); + l->l_flag |= LW_WEXIT; /* will be released when unscheduled */ +} + +struct lwp * +rump_lwproc_curlwp(void) +{ + struct lwp *l = curlwp; + + if (l->l_flag & LW_WEXIT) + return NULL; + return l; +}