lwproc.c revision 1.26 1 /* $NetBSD: lwproc.c,v 1.26 2013/12/16 15:36:29 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.26 2013/12/16 15:36:29 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/ktrace.h>
38 #include <sys/pool.h>
39 #include <sys/proc.h>
40 #include <sys/queue.h>
41 #include <sys/resourcevar.h>
42 #include <sys/uidinfo.h>
43
44 #include <rump/rumpuser.h>
45
46 #include "rump_private.h"
47
48 struct emul *emul_default = &emul_netbsd;
49
50 static void
51 lwproc_proc_free(struct proc *p)
52 {
53 kauth_cred_t cred;
54
55 KASSERT(p->p_stat == SDYING || p->p_stat == SDEAD);
56
57 #ifdef KTRACE
58 if (p->p_tracep) {
59 mutex_enter(&ktrace_lock);
60 ktrderef(p);
61 mutex_exit(&ktrace_lock);
62 }
63 #endif
64
65 mutex_enter(proc_lock);
66
67 KASSERT(p->p_nlwps == 0);
68 KASSERT(LIST_EMPTY(&p->p_lwps));
69
70 LIST_REMOVE(p, p_list);
71 LIST_REMOVE(p, p_sibling);
72 proc_free_pid(p->p_pid); /* decrements nprocs */
73 proc_leavepgrp(p); /* releases proc_lock */
74
75 cred = p->p_cred;
76 chgproccnt(kauth_cred_getuid(cred), -1);
77 if (rump_proc_vfs_release)
78 rump_proc_vfs_release(p);
79
80 lim_free(p->p_limit);
81 pstatsfree(p->p_stats);
82 kauth_cred_free(p->p_cred);
83 proc_finispecific(p);
84
85 mutex_obj_free(p->p_lock);
86 mutex_destroy(&p->p_stmutex);
87 mutex_destroy(&p->p_auxlock);
88 rw_destroy(&p->p_reflock);
89 cv_destroy(&p->p_waitcv);
90 cv_destroy(&p->p_lwpcv);
91
92 /* non-kernel vmspaces are not shared */
93 if (!RUMP_LOCALPROC_P(p)) {
94 KASSERT(p->p_vmspace->vm_refcnt == 1);
95 kmem_free(p->p_vmspace, sizeof(*p->p_vmspace));
96 }
97
98 proc_free_mem(p);
99 }
100
101 /*
102 * Allocate a new process. Mostly mimic fork by
103 * copying the properties of the parent. However, there are some
104 * differences.
105 *
106 * Switch to the new lwp and return a pointer to it.
107 */
108 static struct proc *
109 lwproc_newproc(struct proc *parent, int flags)
110 {
111 uid_t uid = kauth_cred_getuid(parent->p_cred);
112 struct proc *p;
113
114 /* maxproc not enforced */
115 atomic_inc_uint(&nprocs);
116
117 /* allocate process */
118 p = proc_alloc();
119 memset(&p->p_startzero, 0,
120 offsetof(struct proc, p_endzero)
121 - offsetof(struct proc, p_startzero));
122 memcpy(&p->p_startcopy, &parent->p_startcopy,
123 offsetof(struct proc, p_endcopy)
124 - offsetof(struct proc, p_startcopy));
125
126 /* some other garbage we need to zero */
127 p->p_sigacts = NULL;
128 p->p_aio = NULL;
129 p->p_dtrace = NULL;
130 p->p_mqueue_cnt = p->p_exitsig = 0;
131 p->p_flag = p->p_sflag = p->p_slflag = p->p_lflag = p->p_stflag = 0;
132 p->p_trace_enabled = 0;
133 p->p_xstat = p->p_acflag = 0;
134 p->p_stackbase = 0;
135
136 p->p_stats = pstatscopy(parent->p_stats);
137
138 p->p_vmspace = vmspace_kernel();
139 p->p_emul = emul_default;
140 #ifdef __HAVE_SYSCALL_INTERN
141 p->p_emul->e_syscall_intern(p);
142 #endif
143 if (*parent->p_comm)
144 strcpy(p->p_comm, parent->p_comm);
145 else
146 strcpy(p->p_comm, "rumproc");
147
148 if ((flags & RUMP_RFCFDG) == 0)
149 KASSERT(parent == curproc);
150 if (flags & RUMP_RFFDG)
151 p->p_fd = fd_copy();
152 else if (flags & RUMP_RFCFDG)
153 p->p_fd = fd_init(NULL);
154 else
155 fd_share(p);
156
157 lim_addref(parent->p_limit);
158 p->p_limit = parent->p_limit;
159
160 LIST_INIT(&p->p_lwps);
161 LIST_INIT(&p->p_children);
162
163 p->p_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
164 mutex_init(&p->p_stmutex, MUTEX_DEFAULT, IPL_HIGH);
165 mutex_init(&p->p_auxlock, MUTEX_DEFAULT, IPL_NONE);
166 rw_init(&p->p_reflock);
167 cv_init(&p->p_waitcv, "pwait");
168 cv_init(&p->p_lwpcv, "plwp");
169
170 p->p_pptr = parent;
171 p->p_ppid = parent->p_pid;
172 p->p_stat = SACTIVE;
173
174 kauth_proc_fork(parent, p);
175
176 /* initialize cwd in rump kernels with vfs */
177 if (rump_proc_vfs_init)
178 rump_proc_vfs_init(p);
179
180 chgproccnt(uid, 1); /* not enforced */
181
182 /* publish proc various proc lists */
183 mutex_enter(proc_lock);
184 LIST_INSERT_HEAD(&allproc, p, p_list);
185 LIST_INSERT_HEAD(&parent->p_children, p, p_sibling);
186 LIST_INSERT_AFTER(parent, p, p_pglist);
187 mutex_exit(proc_lock);
188
189 return p;
190 }
191
192 static void
193 lwproc_freelwp(struct lwp *l)
194 {
195 struct proc *p;
196
197 p = l->l_proc;
198 mutex_enter(p->p_lock);
199
200 KASSERT(l->l_flag & LW_WEXIT);
201 KASSERT(l->l_refcnt == 0);
202
203 /* ok, zero references, continue with nuke */
204 LIST_REMOVE(l, l_sibling);
205 KASSERT(p->p_nlwps >= 1);
206 if (--p->p_nlwps == 0) {
207 KASSERT(p != &proc0);
208 p->p_stat = SDEAD;
209 }
210 cv_broadcast(&p->p_lwpcv); /* nobody sleeps on this in a rump kernel? */
211 kauth_cred_free(l->l_cred);
212 mutex_exit(p->p_lock);
213
214 mutex_enter(proc_lock);
215 LIST_REMOVE(l, l_list);
216 mutex_exit(proc_lock);
217
218 if (l->l_name)
219 kmem_free(l->l_name, MAXCOMLEN);
220 lwp_finispecific(l);
221
222 rumpuser_curlwpop(RUMPUSER_LWP_DESTROY, l);
223 membar_exit();
224 kmem_free(l, sizeof(*l));
225
226 if (p->p_stat == SDEAD)
227 lwproc_proc_free(p);
228 }
229
230 extern kmutex_t unruntime_lock;
231
232 /*
233 * called with p_lock held, releases lock before return
234 */
235 static void
236 lwproc_makelwp(struct proc *p, struct lwp *l, bool doswitch, bool procmake)
237 {
238
239 p->p_nlwps++;
240 l->l_refcnt = 1;
241 l->l_proc = p;
242
243 l->l_lid = p->p_nlwpid++;
244 LIST_INSERT_HEAD(&p->p_lwps, l, l_sibling);
245
246 l->l_fd = p->p_fd;
247 l->l_cpu = rump_cpu;
248 l->l_target_cpu = rump_cpu; /* Initial target CPU always the same */
249 l->l_stat = LSRUN;
250 l->l_mutex = &unruntime_lock;
251 TAILQ_INIT(&l->l_ld_locks);
252 mutex_exit(p->p_lock);
253
254 lwp_update_creds(l);
255 lwp_initspecific(l);
256
257 membar_enter();
258 rumpuser_curlwpop(RUMPUSER_LWP_CREATE, l);
259 if (doswitch) {
260 rump_lwproc_switch(l);
261 }
262
263 /* filedesc already has refcount 1 when process is created */
264 if (!procmake) {
265 fd_hold(l);
266 }
267
268 mutex_enter(proc_lock);
269 LIST_INSERT_HEAD(&alllwp, l, l_list);
270 mutex_exit(proc_lock);
271 }
272
273 struct lwp *
274 rump__lwproc_alloclwp(struct proc *p)
275 {
276 struct lwp *l;
277 bool newproc = false;
278
279 if (p == NULL) {
280 p = lwproc_newproc(&proc0, 0);
281 newproc = true;
282 }
283
284 l = kmem_zalloc(sizeof(*l), KM_SLEEP);
285
286 mutex_enter(p->p_lock);
287 KASSERT((p->p_sflag & PS_RUMP_LWPEXIT) == 0);
288 lwproc_makelwp(p, l, false, newproc);
289
290 return l;
291 }
292
293 int
294 rump_lwproc_newlwp(pid_t pid)
295 {
296 struct proc *p;
297 struct lwp *l;
298
299 l = kmem_zalloc(sizeof(*l), KM_SLEEP);
300 mutex_enter(proc_lock);
301 p = proc_find_raw(pid);
302 if (p == NULL) {
303 mutex_exit(proc_lock);
304 kmem_free(l, sizeof(*l));
305 return ESRCH;
306 }
307 mutex_enter(p->p_lock);
308 if (p->p_sflag & PS_RUMP_LWPEXIT) {
309 mutex_exit(proc_lock);
310 mutex_exit(p->p_lock);
311 kmem_free(l, sizeof(*l));
312 return EBUSY;
313 }
314 mutex_exit(proc_lock);
315 lwproc_makelwp(p, l, true, false);
316
317 return 0;
318 }
319
320 int
321 rump_lwproc_rfork(int flags)
322 {
323 struct proc *p;
324 struct lwp *l;
325
326 if (flags & ~(RUMP_RFFDG|RUMP_RFCFDG) ||
327 (~flags & (RUMP_RFFDG|RUMP_RFCFDG)) == 0)
328 return EINVAL;
329
330 p = lwproc_newproc(curproc, flags);
331 l = kmem_zalloc(sizeof(*l), KM_SLEEP);
332 mutex_enter(p->p_lock);
333 KASSERT((p->p_sflag & PS_RUMP_LWPEXIT) == 0);
334 lwproc_makelwp(p, l, true, true);
335
336 return 0;
337 }
338
339 /*
340 * Switch to a new process/thread. Release previous one if
341 * deemed to be exiting. This is considered a slow path for
342 * rump kernel entry.
343 */
344 void
345 rump_lwproc_switch(struct lwp *newlwp)
346 {
347 struct lwp *l = curlwp;
348
349 KASSERT(!(l->l_flag & LW_WEXIT) || newlwp);
350
351 if (__predict_false(newlwp && (newlwp->l_pflag & LP_RUNNING)))
352 panic("lwp %p (%d:%d) already running",
353 newlwp, newlwp->l_proc->p_pid, newlwp->l_lid);
354
355 if (newlwp == NULL) {
356 l->l_pflag &= ~LP_RUNNING;
357 l->l_flag |= LW_RUMP_CLEAR;
358 return;
359 }
360
361 /* fd_free() must be called from curlwp context. talk about ugh */
362 if (l->l_flag & LW_WEXIT) {
363 fd_free();
364 }
365
366 KERNEL_UNLOCK_ALL(NULL, &l->l_biglocks);
367 rumpuser_curlwpop(RUMPUSER_LWP_CLEAR, l);
368
369 newlwp->l_cpu = newlwp->l_target_cpu = l->l_cpu;
370 newlwp->l_mutex = l->l_mutex;
371 newlwp->l_pflag |= LP_RUNNING;
372
373 rumpuser_curlwpop(RUMPUSER_LWP_SET, newlwp);
374 curcpu()->ci_curlwp = newlwp;
375 KERNEL_LOCK(newlwp->l_biglocks, NULL);
376
377 /*
378 * Check if the thread should get a signal. This is
379 * mostly to satisfy the "record" rump sigmodel.
380 */
381 mutex_enter(newlwp->l_proc->p_lock);
382 if (sigispending(newlwp, 0)) {
383 newlwp->l_flag |= LW_PENDSIG;
384 }
385 mutex_exit(newlwp->l_proc->p_lock);
386
387 l->l_mutex = &unruntime_lock;
388 l->l_pflag &= ~LP_RUNNING;
389 l->l_flag &= ~LW_PENDSIG;
390 l->l_stat = LSRUN;
391
392 if (l->l_flag & LW_WEXIT) {
393 lwproc_freelwp(l);
394 }
395 }
396
397 /*
398 * Mark the current thread to be released upon return from
399 * kernel.
400 */
401 void
402 rump_lwproc_releaselwp(void)
403 {
404 struct lwp *l = curlwp;
405
406 if (l->l_refcnt == 0 || l->l_flag & LW_WEXIT)
407 panic("releasing non-pertinent lwp");
408
409 rump__lwproc_lwprele();
410 KASSERT(l->l_refcnt == 0 && (l->l_flag & LW_WEXIT));
411 }
412
413 /*
414 * In-kernel routines used to add and remove references for the
415 * current thread. The main purpose is to make it possible for
416 * implicit threads to persist over scheduling operations in
417 * rump kernel drivers. Note that we don't need p_lock in a
418 * rump kernel, since we do refcounting only for curlwp.
419 */
420 void
421 rump__lwproc_lwphold(void)
422 {
423 struct lwp *l = curlwp;
424
425 l->l_refcnt++;
426 l->l_flag &= ~LW_WEXIT;
427 }
428
429 void
430 rump__lwproc_lwprele(void)
431 {
432 struct lwp *l = curlwp;
433
434 l->l_refcnt--;
435 if (l->l_refcnt == 0)
436 l->l_flag |= LW_WEXIT;
437 }
438
439 struct lwp *
440 rump_lwproc_curlwp(void)
441 {
442 struct lwp *l = curlwp;
443
444 if (l->l_flag & LW_WEXIT)
445 return NULL;
446 return l;
447 }
448
449 /* this interface is under construction (like the proverbial 90's web page) */
450 int rump_i_know_what_i_am_doing_with_sysents = 0;
451 void
452 rump_lwproc_sysent_usenative()
453 {
454
455 if (!rump_i_know_what_i_am_doing_with_sysents)
456 panic("don't use rump_lwproc_sysent_usenative()");
457 curproc->p_emul = &emul_netbsd;
458 }
459