xref: /netbsd-src/sys/rump/librump/rumpkern/lwproc.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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