kern_kthread.c revision 104306
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1999 Peter Wemm <peter@FreeBSD.org>
31549Srgrimes * All rights reserved.
41549Srgrimes *
59507Sdg * Redistribution and use in source and binary forms, with or without
69507Sdg * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes *
141541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2158705Scharnier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241541Srgrimes * SUCH DAMAGE.
251541Srgrimes *
261541Srgrimes * $FreeBSD: head/sys/kern/kern_kthread.c 104306 2002-10-01 17:15:53Z jmallett $
271541Srgrimes */
281541Srgrimes
291541Srgrimes#include <sys/param.h>
301541Srgrimes#include <sys/systm.h>
311541Srgrimes#include <sys/kthread.h>
321541Srgrimes#include <sys/lock.h>
331541Srgrimes#include <sys/mutex.h>
341541Srgrimes#include <sys/proc.h>
351541Srgrimes#include <sys/resourcevar.h>
361541Srgrimes#include <sys/signalvar.h>
371541Srgrimes#include <sys/sx.h>
381541Srgrimes#include <sys/unistd.h>
391541Srgrimes#include <sys/wait.h>
401549Srgrimes
411541Srgrimes#include <machine/stdarg.h>
421541Srgrimes
431541Srgrimes/*
441541Srgrimes * Start a kernel process.  This is called after a fork() call in
451541Srgrimes * mi_startup() in the file kern/init_main.c.
461541Srgrimes *
471549Srgrimes * This function is used to start "internal" daemons and intended
481549Srgrimes * to be called from SYSINIT().
499507Sdg */
507695Sdgvoid
511549Srgrimeskproc_start(udata)
521549Srgrimes	const void *udata;
53116226Sobrien{
54116226Sobrien	const struct kproc_desc	*kp = udata;
55116226Sobrien	int error;
561541Srgrimes
571541Srgrimes	error = kthread_create((void (*)(void *))kp->func, NULL,
581541Srgrimes		    kp->global_procpp, 0, "%s", kp->arg0);
591541Srgrimes	if (error)
601541Srgrimes		panic("kproc_start: %s: error %d", kp->arg0, error);
6160041Sphk}
629507Sdg
6312662Sdg/*
6451340Sdillon * Create a kernel process/thread/whatever.  It shares its address space
651541Srgrimes * with proc0 - ie: kernel only.
661541Srgrimes *
6712662Sdg * func is the function to start.
681541Srgrimes * arg is the parameter to pass to function on first startup.
699507Sdg * newpp is the return value pointing to the thread's struct proc.
7031853Sdyson * flags are flags to fork1 (in unistd.h)
711541Srgrimes * fmt and following will be *printf'd into (*newpp)->p_comm (for ps, etc.).
7212662Sdg */
731541Srgrimesint
7492727Salfredkthread_create(void (*func)(void *), void *arg,
7592727Salfred    struct proc **newpp, int flags, const char *fmt, ...)
7692727Salfred{
7792727Salfred	int error;
7892727Salfred	va_list ap;
7992727Salfred	struct thread *td;
8092727Salfred	struct proc *p2;
8192727Salfred
8292727Salfred	if (!proc0.p_stats /* || proc0.p_stats->p_start.tv_sec == 0 */)
8392727Salfred		panic("kthread_create called too soon");
8411943Sbde
851541Srgrimes	error = fork1(&thread0, RFMEM | RFFDG | RFPROC | RFSTOPPED | flags,
86118466Sphk	    &p2);
87118466Sphk	if (error)
88118466Sphk		return error;
89118466Sphk
90118466Sphk	/* save a global descriptor, if desired */
91118466Sphk	if (newpp != NULL)
921541Srgrimes		*newpp = p2;
931541Srgrimes
9479127Sjhb	/* this is a non-swapped system process */
9510556Sdyson	PROC_LOCK(p2);
96104094Sphk	p2->p_flag |= P_SYSTEM | P_KTHREAD;
9779127Sjhb	p2->p_procsig->ps_flag |= PS_NOCLDWAIT;
9879127Sjhb	_PHOLD(p2);
9942957Sdillon	PROC_UNLOCK(p2);
10079127Sjhb
10179127Sjhb	/* set up arg0 for 'ps', et al */
10279127Sjhb	va_start(ap, fmt);
1031541Srgrimes	vsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap);
1041541Srgrimes	va_end(ap);
1051541Srgrimes
10698604Salc	/* call the processes' main()... */
10798604Salc	td = FIRST_THREAD_IN_PROC(p2);
1081541Srgrimes	cpu_set_fork_handler(td, func, arg);
1099507Sdg	TD_SET_CAN_RUN(td);
11040286Sdg
11128751Sbde	/* Delay putting it on the run queue until now. */
1121541Srgrimes	mtx_lock_spin(&sched_lock);
1139456Sdg	p2->p_sflag |= PS_INMEM;
1141541Srgrimes	if (!(flags & RFSTOPPED)) {
1151541Srgrimes		setrunqueue(td);
1161541Srgrimes	}
1171541Srgrimes	mtx_unlock_spin(&sched_lock);
1181541Srgrimes
1191541Srgrimes	return 0;
1201827Sdg}
1211541Srgrimes
1229411Sdgvoid
1239411Sdgkthread_exit(int ecode)
124103923Sjeff{
125103923Sjeff	struct thread *td;
12698604Salc	struct proc *p;
1271541Srgrimes
1289411Sdg	td = curthread;
1299411Sdg	p = td->td_proc;
1301541Srgrimes	sx_xlock(&proctree_lock);
131101308Sjeff	PROC_LOCK(p);
132101308Sjeff	proc_reparent(p, initproc);
133101308Sjeff	PROC_UNLOCK(p);
134101308Sjeff	sx_xunlock(&proctree_lock);
1359411Sdg	exit1(td, W_EXITCODE(ecode, 0));
136101308Sjeff}
137101308Sjeff
1389411Sdg/*
1399411Sdg * Advise a kernel process to suspend (or resume) in its main loop.
1409411Sdg * Participation is voluntary.
1419411Sdg */
1429411Sdgint
143114074Salckthread_suspend(struct proc *p, int timo)
144114074Salc{
145114074Salc	/*
146114074Salc	 * Make sure this is indeed a system process and we can safely
147114074Salc	 * use the p_siglist field.
1489507Sdg	 */
1495455Sdg	PROC_LOCK(p);
15032071Sdyson	if ((p->p_flag & P_KTHREAD) == 0) {
15132071Sdyson		PROC_UNLOCK(p);
15232071Sdyson		return (EINVAL);
1539507Sdg	}
1541541Srgrimes	SIGADDSET(p->p_siglist, SIGSTOP);
1551541Srgrimes	wakeup(p);
1561541Srgrimes	return msleep(&p->p_siglist, &p->p_mtx, PPAUSE | PDROP, "suspkt", timo);
15740286Sdg}
1581827Sdg
15940286Sdgint
1601549Srgrimeskthread_resume(struct proc *p)
1619507Sdg{
1629507Sdg	/*
1631541Srgrimes	 * Make sure this is indeed a system process and we can safely
16432286Sdyson	 * use the p_siglist field.
165114074Salc	 */
1661541Srgrimes	PROC_LOCK(p);
167101308Sjeff	if ((p->p_flag & P_KTHREAD) == 0) {
16898604Salc		PROC_UNLOCK(p);
169101308Sjeff		return (EINVAL);
170101308Sjeff	}
171101308Sjeff	SIGDELSET(p->p_siglist, SIGSTOP);
1729411Sdg	PROC_UNLOCK(p);
1739411Sdg	wakeup(&p->p_siglist);
174101308Sjeff	return (0);
17598604Salc}
1769507Sdg
1771541Srgrimesvoid
1781541Srgrimeskthread_suspend_check(struct proc *p)
179114774Salc{
180114774Salc	PROC_LOCK(p);
181114774Salc	while (SIGISMEMBER(p->p_siglist, SIGSTOP)) {
18212820Sphk		wakeup(&p->p_siglist);
1839507Sdg		msleep(&p->p_siglist, &p->p_mtx, PPAUSE, "ktsusp", 0);
1849507Sdg	}
1851541Srgrimes	PROC_UNLOCK(p);
18679242Sdillon}
1871541Srgrimes