lwproc.c revision 1.14
1/* $NetBSD: lwproc.c,v 1.14 2011/02/10 13:31:30 pooka Exp $ */ 2 3/* 4 * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__KERNEL_RCSID(0, "$NetBSD: lwproc.c,v 1.14 2011/02/10 13:31:30 pooka Exp $"); 30 31#include <sys/param.h> 32#include <sys/atomic.h> 33#include <sys/filedesc.h> 34#include <sys/kauth.h> 35#include <sys/kmem.h> 36#include <sys/lwp.h> 37#include <sys/pool.h> 38#include <sys/proc.h> 39#include <sys/queue.h> 40#include <sys/resourcevar.h> 41#include <sys/uidinfo.h> 42 43#include <rump/rumpuser.h> 44 45#include "rump_private.h" 46 47static void 48lwproc_proc_free(struct proc *p) 49{ 50 kauth_cred_t cred; 51 52 mutex_enter(proc_lock); 53 54 KASSERT(p->p_nlwps == 0); 55 KASSERT(LIST_EMPTY(&p->p_lwps)); 56 KASSERT(p->p_stat == SACTIVE || p->p_stat == SDYING || 57 p->p_stat == SDEAD); 58 59 LIST_REMOVE(p, p_list); 60 LIST_REMOVE(p, p_sibling); 61 proc_free_pid(p->p_pid); /* decrements nprocs */ 62 proc_leavepgrp(p); /* releases proc_lock */ 63 64 cred = p->p_cred; 65 chgproccnt(kauth_cred_getuid(cred), -1); 66 if (rump_proc_vfs_release) 67 rump_proc_vfs_release(p); 68 69 limfree(p->p_limit); 70 pstatsfree(p->p_stats); 71 kauth_cred_free(p->p_cred); 72 proc_finispecific(p); 73 74 mutex_obj_free(p->p_lock); 75 mutex_destroy(&p->p_stmutex); 76 mutex_destroy(&p->p_auxlock); 77 rw_destroy(&p->p_reflock); 78 cv_destroy(&p->p_waitcv); 79 cv_destroy(&p->p_lwpcv); 80 81 /* non-kernel vmspaces are not shared */ 82 if (!RUMP_LOCALPROC_P(p)) { 83 KASSERT(p->p_vmspace->vm_refcnt == 1); 84 kmem_free(p->p_vmspace, sizeof(*p->p_vmspace)); 85 } 86 87 proc_free_mem(p); 88} 89 90/* 91 * Allocate a new process. Mostly mimic fork by 92 * copying the properties of the parent. However, there are some 93 * differences. For example, we never share the fd table. 94 * 95 * Switch to the new lwp and return a pointer to it. 96 */ 97static struct proc * 98lwproc_newproc(struct proc *parent, int flags) 99{ 100 uid_t uid = kauth_cred_getuid(parent->p_cred); 101 struct proc *p; 102 103 /* maxproc not enforced */ 104 atomic_inc_uint(&nprocs); 105 106 /* allocate process */ 107 p = proc_alloc(); 108 memset(&p->p_startzero, 0, 109 offsetof(struct proc, p_endzero) 110 - offsetof(struct proc, p_startzero)); 111 memcpy(&p->p_startcopy, &parent->p_startcopy, 112 offsetof(struct proc, p_endcopy) 113 - offsetof(struct proc, p_startcopy)); 114 115 p->p_stats = pstatscopy(parent->p_stats); 116 117 p->p_vmspace = vmspace_kernel(); 118 p->p_emul = &emul_netbsd; 119 if (*parent->p_comm) 120 strcpy(p->p_comm, parent->p_comm); 121 else 122 strcpy(p->p_comm, "rumproc"); 123 124 if ((flags & RUMP_RFCFDG) == 0) 125 KASSERT(parent == curproc); 126 if (flags & RUMP_RFFDG) 127 p->p_fd = fd_copy(); 128 else if (flags & RUMP_RFCFDG) 129 p->p_fd = fd_init(NULL); 130 else 131 fd_share(p); 132 133 lim_addref(parent->p_limit); 134 p->p_limit = parent->p_limit; 135 136 LIST_INIT(&p->p_lwps); 137 LIST_INIT(&p->p_children); 138 139 p->p_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); 140 mutex_init(&p->p_stmutex, MUTEX_DEFAULT, IPL_NONE); 141 mutex_init(&p->p_auxlock, MUTEX_DEFAULT, IPL_NONE); 142 rw_init(&p->p_reflock); 143 cv_init(&p->p_waitcv, "pwait"); 144 cv_init(&p->p_lwpcv, "plwp"); 145 146 p->p_pptr = parent; 147 p->p_ppid = parent->p_pid; 148 p->p_stat = SACTIVE; 149 150 kauth_proc_fork(parent, p); 151 152 /* initialize cwd in rump kernels with vfs */ 153 if (rump_proc_vfs_init) 154 rump_proc_vfs_init(p); 155 156 chgproccnt(uid, 1); /* not enforced */ 157 158 /* publish proc various proc lists */ 159 mutex_enter(proc_lock); 160 LIST_INSERT_HEAD(&allproc, p, p_list); 161 LIST_INSERT_HEAD(&parent->p_children, p, p_sibling); 162 LIST_INSERT_AFTER(parent, p, p_pglist); 163 mutex_exit(proc_lock); 164 165 return p; 166} 167 168static void 169lwproc_freelwp(struct lwp *l) 170{ 171 struct proc *p; 172 bool freeproc; 173 174 p = l->l_proc; 175 mutex_enter(p->p_lock); 176 177 /* XXX: l_refcnt */ 178 KASSERT(l->l_flag & LW_WEXIT); 179 KASSERT(l->l_refcnt == 0); 180 181 /* ok, zero references, continue with nuke */ 182 LIST_REMOVE(l, l_sibling); 183 KASSERT(p->p_nlwps >= 1); 184 if (--p->p_nlwps == 0) { 185 KASSERT(p != &proc0); 186 p->p_stat = SDEAD; 187 } 188 freeproc = p->p_nlwps == 0; 189 cv_broadcast(&p->p_lwpcv); /* nobody sleeps on this in rump? */ 190 kauth_cred_free(l->l_cred); 191 mutex_exit(p->p_lock); 192 193 mutex_enter(proc_lock); 194 LIST_REMOVE(l, l_list); 195 mutex_exit(proc_lock); 196 197 if (l->l_name) 198 kmem_free(l->l_name, MAXCOMLEN); 199 lwp_finispecific(l); 200 201 kmem_free(l, sizeof(*l)); 202 203 if (p->p_stat == SDEAD) 204 lwproc_proc_free(p); 205} 206 207extern kmutex_t unruntime_lock; 208 209/* 210 * called with p_lock held, releases lock before return 211 */ 212static void 213lwproc_makelwp(struct proc *p, struct lwp *l, bool doswitch, bool procmake) 214{ 215 216 p->p_nlwps++; 217 l->l_refcnt = 1; 218 l->l_proc = p; 219 220 l->l_lid = p->p_nlwpid++; 221 LIST_INSERT_HEAD(&p->p_lwps, l, l_sibling); 222 mutex_exit(p->p_lock); 223 224 lwp_update_creds(l); 225 226 l->l_fd = p->p_fd; 227 l->l_cpu = rump_cpu; 228 l->l_target_cpu = rump_cpu; /* Initial target CPU always the same */ 229 l->l_stat = LSRUN; 230 l->l_mutex = &unruntime_lock; 231 TAILQ_INIT(&l->l_ld_locks); 232 233 lwp_initspecific(l); 234 235 if (doswitch) { 236 rump_lwproc_switch(l); 237 } 238 239 /* filedesc already has refcount 1 when process is created */ 240 if (!procmake) { 241 fd_hold(l); 242 } 243 244 mutex_enter(proc_lock); 245 LIST_INSERT_HEAD(&alllwp, l, l_list); 246 mutex_exit(proc_lock); 247} 248 249struct lwp * 250rump__lwproc_alloclwp(struct proc *p) 251{ 252 struct lwp *l; 253 bool newproc = false; 254 255 if (p == NULL) { 256 p = lwproc_newproc(&proc0, 0); 257 newproc = true; 258 } 259 260 l = kmem_zalloc(sizeof(*l), KM_SLEEP); 261 262 mutex_enter(p->p_lock); 263 lwproc_makelwp(p, l, false, newproc); 264 265 return l; 266} 267 268int 269rump_lwproc_newlwp(pid_t pid) 270{ 271 struct proc *p; 272 struct lwp *l; 273 274 l = kmem_zalloc(sizeof(*l), KM_SLEEP); 275 mutex_enter(proc_lock); 276 p = proc_find_raw(pid); 277 if (p == NULL) { 278 mutex_exit(proc_lock); 279 kmem_free(l, sizeof(*l)); 280 return ESRCH; 281 } 282 mutex_enter(p->p_lock); 283 mutex_exit(proc_lock); 284 lwproc_makelwp(p, l, true, false); 285 286 return 0; 287} 288 289int 290rump_lwproc_rfork(int flags) 291{ 292 struct proc *p; 293 struct lwp *l; 294 295 if (flags & ~(RUMP_RFFDG|RUMP_RFCFDG) || 296 (~flags & (RUMP_RFFDG|RUMP_RFCFDG)) == 0) 297 return EINVAL; 298 299 p = lwproc_newproc(curproc, flags); 300 l = kmem_zalloc(sizeof(*l), KM_SLEEP); 301 mutex_enter(p->p_lock); 302 lwproc_makelwp(p, l, true, true); 303 304 return 0; 305} 306 307/* 308 * Switch to a new process/thread. Release previous one if 309 * deemed to be exiting. This is considered a slow path for 310 * rump kernel entry. 311 */ 312void 313rump_lwproc_switch(struct lwp *newlwp) 314{ 315 struct lwp *l = curlwp; 316 317 KASSERT(!(l->l_flag & LW_WEXIT) || newlwp); 318 319 if (__predict_false(newlwp && (newlwp->l_pflag & LP_RUNNING))) 320 panic("lwp %p (%d:%d) already running", 321 newlwp, newlwp->l_proc->p_pid, newlwp->l_lid); 322 323 if (newlwp == NULL) { 324 l->l_pflag &= ~LP_RUNNING; 325 l->l_flag |= LW_RUMP_CLEAR; 326 return; 327 } 328 329 /* fd_free() must be called from curlwp context. talk about ugh */ 330 if (l->l_flag & LW_WEXIT) { 331 fd_free(); 332 } 333 334 rumpuser_set_curlwp(NULL); 335 336 newlwp->l_cpu = newlwp->l_target_cpu = l->l_cpu; 337 newlwp->l_mutex = l->l_mutex; 338 newlwp->l_pflag |= LP_RUNNING; 339 340 rumpuser_set_curlwp(newlwp); 341 342 /* 343 * Check if the thread should get a signal. This is 344 * mostly to satisfy the "record" rump sigmodel. 345 */ 346 mutex_enter(newlwp->l_proc->p_lock); 347 if (sigispending(newlwp, 0)) { 348 newlwp->l_flag |= LW_PENDSIG; 349 } 350 mutex_exit(newlwp->l_proc->p_lock); 351 352 l->l_mutex = &unruntime_lock; 353 l->l_pflag &= ~LP_RUNNING; 354 l->l_flag &= ~LW_PENDSIG; 355 l->l_stat = LSRUN; 356 357 if (l->l_flag & LW_WEXIT) { 358 lwproc_freelwp(l); 359 } 360} 361 362void 363rump_lwproc_releaselwp(void) 364{ 365 struct proc *p; 366 struct lwp *l = curlwp; 367 368 if (l->l_refcnt == 0 && l->l_flag & LW_WEXIT) 369 panic("releasing non-pertinent lwp"); 370 371 p = l->l_proc; 372 mutex_enter(p->p_lock); 373 KASSERT(l->l_refcnt != 0); 374 l->l_refcnt--; 375 mutex_exit(p->p_lock); 376 l->l_flag |= LW_WEXIT; /* will be released when unscheduled */ 377} 378 379struct lwp * 380rump_lwproc_curlwp(void) 381{ 382 struct lwp *l = curlwp; 383 384 if (l->l_flag & LW_WEXIT) 385 return NULL; 386 return l; 387} 388