19c8b8baaSPeter Wemm /* 29c8b8baaSPeter Wemm * Copyright (c) 1999 Peter Wemm <peter@FreeBSD.org> 39c8b8baaSPeter Wemm * All rights reserved. 49c8b8baaSPeter Wemm * 59c8b8baaSPeter Wemm * Redistribution and use in source and binary forms, with or without 69c8b8baaSPeter Wemm * modification, are permitted provided that the following conditions 79c8b8baaSPeter Wemm * are met: 89c8b8baaSPeter Wemm * 1. Redistributions of source code must retain the above copyright 99c8b8baaSPeter Wemm * notice, this list of conditions and the following disclaimer. 109c8b8baaSPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 119c8b8baaSPeter Wemm * notice, this list of conditions and the following disclaimer in the 129c8b8baaSPeter Wemm * documentation and/or other materials provided with the distribution. 139c8b8baaSPeter Wemm * 149c8b8baaSPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 159c8b8baaSPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 169c8b8baaSPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 179c8b8baaSPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 189c8b8baaSPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 199c8b8baaSPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 209c8b8baaSPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 219c8b8baaSPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 229c8b8baaSPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 239c8b8baaSPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 249c8b8baaSPeter Wemm * SUCH DAMAGE. 259c8b8baaSPeter Wemm * 269c8b8baaSPeter Wemm * $FreeBSD$ 279c8b8baaSPeter Wemm */ 289c8b8baaSPeter Wemm 299c8b8baaSPeter Wemm #include <sys/param.h> 309c8b8baaSPeter Wemm #include <sys/systm.h> 319c8b8baaSPeter Wemm #include <sys/kthread.h> 3298f03f90SJake Burkholder #include <sys/lock.h> 331005a129SJohn Baldwin #include <sys/mutex.h> 341005a129SJohn Baldwin #include <sys/proc.h> 3531008641SWarner Losh #include <sys/resourcevar.h> 365e950839SLuoqi Chen #include <sys/signalvar.h> 371005a129SJohn Baldwin #include <sys/sx.h> 389c8b8baaSPeter Wemm #include <sys/unistd.h> 399c8b8baaSPeter Wemm #include <sys/wait.h> 409c8b8baaSPeter Wemm 419c8b8baaSPeter Wemm #include <machine/stdarg.h> 429c8b8baaSPeter Wemm 439c8b8baaSPeter Wemm /* 449c8b8baaSPeter Wemm * Start a kernel process. This is called after a fork() call in 459c8b8baaSPeter Wemm * mi_startup() in the file kern/init_main.c. 469c8b8baaSPeter Wemm * 479c8b8baaSPeter Wemm * This function is used to start "internal" daemons and intended 489c8b8baaSPeter Wemm * to be called from SYSINIT(). 499c8b8baaSPeter Wemm */ 509c8b8baaSPeter Wemm void 519c8b8baaSPeter Wemm kproc_start(udata) 529c8b8baaSPeter Wemm const void *udata; 539c8b8baaSPeter Wemm { 549c8b8baaSPeter Wemm const struct kproc_desc *kp = udata; 559c8b8baaSPeter Wemm int error; 569c8b8baaSPeter Wemm 579c8b8baaSPeter Wemm error = kthread_create((void (*)(void *))kp->func, NULL, 582d075e99SKris Kennaway kp->global_procpp, 0, "%s", kp->arg0); 599c8b8baaSPeter Wemm if (error) 609c8b8baaSPeter Wemm panic("kproc_start: %s: error %d", kp->arg0, error); 619c8b8baaSPeter Wemm } 629c8b8baaSPeter Wemm 639c8b8baaSPeter Wemm /* 640384fff8SJason Evans * Create a kernel process/thread/whatever. It shares its address space 659c8b8baaSPeter Wemm * with proc0 - ie: kernel only. 660384fff8SJason Evans * 670384fff8SJason Evans * func is the function to start. 680384fff8SJason Evans * arg is the parameter to pass to function on first startup. 690384fff8SJason Evans * newpp is the return value pointing to the thread's struct proc. 700384fff8SJason Evans * flags are flags to fork1 (in unistd.h) 710384fff8SJason Evans * fmt and following will be *printf'd into (*newpp)->p_comm (for ps, etc.). 729c8b8baaSPeter Wemm */ 739c8b8baaSPeter Wemm int 749c8b8baaSPeter Wemm kthread_create(void (*func)(void *), void *arg, 750384fff8SJason Evans struct proc **newpp, int flags, const char *fmt, ...) 769c8b8baaSPeter Wemm { 779c8b8baaSPeter Wemm int error; 789c8b8baaSPeter Wemm va_list ap; 7971fad9fdSJulian Elischer struct thread *td; 809c8b8baaSPeter Wemm struct proc *p2; 819c8b8baaSPeter Wemm 820384fff8SJason Evans if (!proc0.p_stats /* || proc0.p_stats->p_start.tv_sec == 0 */) 830384fff8SJason Evans panic("kthread_create called too soon"); 840384fff8SJason Evans 852b8a08afSPeter Wemm error = fork1(&thread0, RFMEM | RFFDG | RFPROC | RFSTOPPED | flags, 862b8a08afSPeter Wemm &p2); 879c8b8baaSPeter Wemm if (error) 889c8b8baaSPeter Wemm return error; 899c8b8baaSPeter Wemm 909c8b8baaSPeter Wemm /* save a global descriptor, if desired */ 919c8b8baaSPeter Wemm if (newpp != NULL) 929c8b8baaSPeter Wemm *newpp = p2; 939c8b8baaSPeter Wemm 949c8b8baaSPeter Wemm /* this is a non-swapped system process */ 95f1dea27dSJohn Baldwin PROC_LOCK(p2); 96f1dea27dSJohn Baldwin p2->p_flag |= P_SYSTEM | P_KTHREAD; 97645682fdSLuoqi Chen p2->p_procsig->ps_flag |= PS_NOCLDWAIT; 986451855fSJohn Baldwin _PHOLD(p2); 99f1dea27dSJohn Baldwin PROC_UNLOCK(p2); 1009c8b8baaSPeter Wemm 1019c8b8baaSPeter Wemm /* set up arg0 for 'ps', et al */ 1029c8b8baaSPeter Wemm va_start(ap, fmt); 1039c8b8baaSPeter Wemm vsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap); 1049c8b8baaSPeter Wemm va_end(ap); 1059c8b8baaSPeter Wemm 1069c8b8baaSPeter Wemm /* call the processes' main()... */ 10771fad9fdSJulian Elischer td = FIRST_THREAD_IN_PROC(p2); 10871fad9fdSJulian Elischer cpu_set_fork_handler(td, func, arg); 10971fad9fdSJulian Elischer TD_SET_CAN_RUN(td); 1109c8b8baaSPeter Wemm 111960d3c68SJohn Baldwin /* Delay putting it on the run queue until now. */ 1129ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 113f1dea27dSJohn Baldwin p2->p_sflag |= PS_INMEM; 114f1dea27dSJohn Baldwin if (!(flags & RFSTOPPED)) { 11571fad9fdSJulian Elischer setrunqueue(td); 116960d3c68SJohn Baldwin } 1179ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 118960d3c68SJohn Baldwin 1199c8b8baaSPeter Wemm return 0; 1209c8b8baaSPeter Wemm } 1219c8b8baaSPeter Wemm 1229c8b8baaSPeter Wemm void 1239c8b8baaSPeter Wemm kthread_exit(int ecode) 1249c8b8baaSPeter Wemm { 125658c434dSPeter Wemm struct thread *td; 126658c434dSPeter Wemm struct proc *p; 12798f03f90SJake Burkholder 128658c434dSPeter Wemm td = curthread; 129658c434dSPeter Wemm p = td->td_proc; 1301005a129SJohn Baldwin sx_xlock(&proctree_lock); 1315b1927bcSMatthew Dillon PROC_LOCK(p); 1325b1927bcSMatthew Dillon proc_reparent(p, initproc); 1335b1927bcSMatthew Dillon PROC_UNLOCK(p); 1341005a129SJohn Baldwin sx_xunlock(&proctree_lock); 135658c434dSPeter Wemm exit1(td, W_EXITCODE(ecode, 0)); 1369c8b8baaSPeter Wemm } 1379c8b8baaSPeter Wemm 1385e950839SLuoqi Chen /* 1395e950839SLuoqi Chen * Advise a kernel process to suspend (or resume) in its main loop. 1405e950839SLuoqi Chen * Participation is voluntary. 1415e950839SLuoqi Chen */ 1425e950839SLuoqi Chen int 143ffc831daSJohn Baldwin kthread_suspend(struct proc *p, int timo) 1445e950839SLuoqi Chen { 1455e950839SLuoqi Chen /* 1465e950839SLuoqi Chen * Make sure this is indeed a system process and we can safely 1475e950839SLuoqi Chen * use the p_siglist field. 1485e950839SLuoqi Chen */ 1496451855fSJohn Baldwin PROC_LOCK(p); 1506451855fSJohn Baldwin if ((p->p_flag & P_KTHREAD) == 0) { 1516451855fSJohn Baldwin PROC_UNLOCK(p); 1525e950839SLuoqi Chen return (EINVAL); 1536451855fSJohn Baldwin } 1545e950839SLuoqi Chen SIGADDSET(p->p_siglist, SIGSTOP); 1558f0d41d3SPeter Wemm wakeup(p); 1566451855fSJohn Baldwin return msleep(&p->p_siglist, &p->p_mtx, PPAUSE | PDROP, "suspkt", timo); 1575e950839SLuoqi Chen } 1585e950839SLuoqi Chen 1595e950839SLuoqi Chen int 160ffc831daSJohn Baldwin kthread_resume(struct proc *p) 1615e950839SLuoqi Chen { 1625e950839SLuoqi Chen /* 1635e950839SLuoqi Chen * Make sure this is indeed a system process and we can safely 1645e950839SLuoqi Chen * use the p_siglist field. 1655e950839SLuoqi Chen */ 1666451855fSJohn Baldwin PROC_LOCK(p); 1676451855fSJohn Baldwin if ((p->p_flag & P_KTHREAD) == 0) { 1686451855fSJohn Baldwin PROC_UNLOCK(p); 1695e950839SLuoqi Chen return (EINVAL); 1706451855fSJohn Baldwin } 1715e950839SLuoqi Chen SIGDELSET(p->p_siglist, SIGSTOP); 1726451855fSJohn Baldwin PROC_UNLOCK(p); 1736451855fSJohn Baldwin wakeup(&p->p_siglist); 1745e950839SLuoqi Chen return (0); 1755e950839SLuoqi Chen } 1765e950839SLuoqi Chen 1775e950839SLuoqi Chen void 178ffc831daSJohn Baldwin kthread_suspend_check(struct proc *p) 1795e950839SLuoqi Chen { 1806451855fSJohn Baldwin PROC_LOCK(p); 1815e950839SLuoqi Chen while (SIGISMEMBER(p->p_siglist, SIGSTOP)) { 1826451855fSJohn Baldwin wakeup(&p->p_siglist); 1836451855fSJohn Baldwin msleep(&p->p_siglist, &p->p_mtx, PPAUSE, "ktsusp", 0); 1845e950839SLuoqi Chen } 1856451855fSJohn Baldwin PROC_UNLOCK(p); 1865e950839SLuoqi Chen } 187