The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_kthread.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1999 Peter Wemm <peter@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/8.1/sys/kern/kern_kthread.c 207916 2010-05-11 13:18:41Z kib $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kthread.h>
   33 #include <sys/lock.h>
   34 #include <sys/mutex.h>
   35 #include <sys/proc.h>
   36 #include <sys/resourcevar.h>
   37 #include <sys/signalvar.h>
   38 #include <sys/sx.h>
   39 #include <sys/unistd.h>
   40 #include <sys/wait.h>
   41 #include <sys/sched.h>
   42 #include <vm/vm.h>
   43 #include <vm/vm_extern.h>
   44 
   45 #include <machine/stdarg.h>
   46 
   47 /*
   48  * Start a kernel process.  This is called after a fork() call in
   49  * mi_startup() in the file kern/init_main.c.
   50  *
   51  * This function is used to start "internal" daemons and intended
   52  * to be called from SYSINIT().
   53  */
   54 void
   55 kproc_start(udata)
   56         const void *udata;
   57 {
   58         const struct kproc_desc *kp = udata;
   59         int error;
   60 
   61         error = kproc_create((void (*)(void *))kp->func, NULL,
   62                     kp->global_procpp, 0, 0, "%s", kp->arg0);
   63         if (error)
   64                 panic("kproc_start: %s: error %d", kp->arg0, error);
   65 }
   66 
   67 /*
   68  * Create a kernel process/thread/whatever.  It shares its address space
   69  * with proc0 - ie: kernel only.
   70  *
   71  * func is the function to start.
   72  * arg is the parameter to pass to function on first startup.
   73  * newpp is the return value pointing to the thread's struct proc.
   74  * flags are flags to fork1 (in unistd.h)
   75  * fmt and following will be *printf'd into (*newpp)->p_comm (for ps, etc.).
   76  */
   77 int
   78 kproc_create(void (*func)(void *), void *arg,
   79     struct proc **newpp, int flags, int pages, const char *fmt, ...)
   80 {
   81         int error;
   82         va_list ap;
   83         struct thread *td;
   84         struct proc *p2;
   85 
   86         if (!proc0.p_stats)
   87                 panic("kproc_create called too soon");
   88 
   89         error = fork1(&thread0, RFMEM | RFFDG | RFPROC | RFSTOPPED | flags,
   90             pages, &p2);
   91         if (error)
   92                 return error;
   93 
   94         /* save a global descriptor, if desired */
   95         if (newpp != NULL)
   96                 *newpp = p2;
   97 
   98         /* this is a non-swapped system process */
   99         PROC_LOCK(p2);
  100         td = FIRST_THREAD_IN_PROC(p2);
  101         p2->p_flag |= P_SYSTEM | P_KTHREAD;
  102         td->td_pflags |= TDP_KTHREAD;
  103         mtx_lock(&p2->p_sigacts->ps_mtx);
  104         p2->p_sigacts->ps_flag |= PS_NOCLDWAIT;
  105         mtx_unlock(&p2->p_sigacts->ps_mtx);
  106         PROC_UNLOCK(p2);
  107 
  108         /* set up arg0 for 'ps', et al */
  109         va_start(ap, fmt);
  110         vsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap);
  111         va_end(ap);
  112         /* set up arg0 for 'ps', et al */
  113         va_start(ap, fmt);
  114         vsnprintf(td->td_name, sizeof(td->td_name), fmt, ap);
  115         va_end(ap);
  116 
  117         /* call the processes' main()... */
  118         cpu_set_fork_handler(td, func, arg);
  119         TD_SET_CAN_RUN(td);
  120 
  121         /* Delay putting it on the run queue until now. */
  122         if (!(flags & RFSTOPPED)) {
  123                 thread_lock(td);
  124                 sched_add(td, SRQ_BORING); 
  125                 thread_unlock(td);
  126         }
  127 
  128         return 0;
  129 }
  130 
  131 void
  132 kproc_exit(int ecode)
  133 {
  134         struct thread *td;
  135         struct proc *p;
  136 
  137         td = curthread;
  138         p = td->td_proc;
  139 
  140         /*
  141          * Reparent curthread from proc0 to init so that the zombie
  142          * is harvested.
  143          */
  144         sx_xlock(&proctree_lock);
  145         PROC_LOCK(p);
  146         proc_reparent(p, initproc);
  147         PROC_UNLOCK(p);
  148         sx_xunlock(&proctree_lock);
  149 
  150         /*
  151          * Wakeup anyone waiting for us to exit.
  152          */
  153         wakeup(p);
  154 
  155         /* Buh-bye! */
  156         exit1(td, W_EXITCODE(ecode, 0));
  157 }
  158 
  159 /*
  160  * Advise a kernel process to suspend (or resume) in its main loop.
  161  * Participation is voluntary.
  162  */
  163 int
  164 kproc_suspend(struct proc *p, int timo)
  165 {
  166         /*
  167          * Make sure this is indeed a system process and we can safely
  168          * use the p_siglist field.
  169          */
  170         PROC_LOCK(p);
  171         if ((p->p_flag & P_KTHREAD) == 0) {
  172                 PROC_UNLOCK(p);
  173                 return (EINVAL);
  174         }
  175         SIGADDSET(p->p_siglist, SIGSTOP);
  176         wakeup(p);
  177         return msleep(&p->p_siglist, &p->p_mtx, PPAUSE | PDROP, "suspkp", timo);
  178 }
  179 
  180 int
  181 kproc_resume(struct proc *p)
  182 {
  183         /*
  184          * Make sure this is indeed a system process and we can safely
  185          * use the p_siglist field.
  186          */
  187         PROC_LOCK(p);
  188         if ((p->p_flag & P_KTHREAD) == 0) {
  189                 PROC_UNLOCK(p);
  190                 return (EINVAL);
  191         }
  192         SIGDELSET(p->p_siglist, SIGSTOP);
  193         PROC_UNLOCK(p);
  194         wakeup(&p->p_siglist);
  195         return (0);
  196 }
  197 
  198 void
  199 kproc_suspend_check(struct proc *p)
  200 {
  201         PROC_LOCK(p);
  202         while (SIGISMEMBER(p->p_siglist, SIGSTOP)) {
  203                 wakeup(&p->p_siglist);
  204                 msleep(&p->p_siglist, &p->p_mtx, PPAUSE, "kpsusp", 0);
  205         }
  206         PROC_UNLOCK(p);
  207 }
  208 
  209 
  210 /*
  211  * Start a kernel thread.  
  212  *
  213  * This function is used to start "internal" daemons and intended
  214  * to be called from SYSINIT().
  215  */
  216 
  217 void
  218 kthread_start(udata)
  219         const void *udata;
  220 {
  221         const struct kthread_desc       *kp = udata;
  222         int error;
  223 
  224         error = kthread_add((void (*)(void *))kp->func, NULL,
  225                     NULL, kp->global_threadpp, 0, 0, "%s", kp->arg0);
  226         if (error)
  227                 panic("kthread_start: %s: error %d", kp->arg0, error);
  228 }
  229 
  230 /*
  231  * Create a kernel thread.  It shares its address space
  232  * with proc0 - ie: kernel only.
  233  *
  234  * func is the function to start.
  235  * arg is the parameter to pass to function on first startup.
  236  * newtdp is the return value pointing to the thread's struct thread.
  237  *  ** XXX fix this --> flags are flags to fork1 (in unistd.h) 
  238  * fmt and following will be *printf'd into (*newtd)->td_name (for ps, etc.).
  239  */
  240 int
  241 kthread_add(void (*func)(void *), void *arg, struct proc *p,
  242     struct thread **newtdp, int flags, int pages, const char *fmt, ...)
  243 {
  244         va_list ap;
  245         struct thread *newtd, *oldtd;
  246 
  247         if (!proc0.p_stats)
  248                 panic("kthread_add called too soon");
  249 
  250         /* If no process supplied, put it on proc0 */
  251         if (p == NULL) {
  252                 p = &proc0;
  253                 oldtd = &thread0;
  254         } else {
  255                 oldtd = FIRST_THREAD_IN_PROC(p);
  256         }
  257 
  258         /* Initialize our new td  */
  259         newtd = thread_alloc(pages);
  260         if (newtd == NULL)
  261                 return (ENOMEM);
  262 
  263         bzero(&newtd->td_startzero,
  264             __rangeof(struct thread, td_startzero, td_endzero));
  265         bzero(&newtd->td_rux, sizeof(newtd->td_rux));
  266 /* XXX check if we should zero. */
  267         bcopy(&oldtd->td_startcopy, &newtd->td_startcopy,
  268             __rangeof(struct thread, td_startcopy, td_endcopy));
  269 
  270         /* set up arg0 for 'ps', et al */
  271         va_start(ap, fmt);
  272         vsnprintf(newtd->td_name, sizeof(newtd->td_name), fmt, ap);
  273         va_end(ap);
  274 
  275         newtd->td_proc = p;  /* needed for cpu_set_upcall */
  276 
  277         /* XXX optimise this probably? */
  278         /* On x86 (and probably the others too) it is way too full of junk */
  279         /* Needs a better name */
  280         cpu_set_upcall(newtd, oldtd);
  281         /* put the designated function(arg) as the resume context */
  282         cpu_set_fork_handler(newtd, func, arg);
  283 
  284         newtd->td_pflags |= TDP_KTHREAD;
  285         newtd->td_ucred = crhold(p->p_ucred);
  286 
  287         /* this code almost the same as create_thread() in kern_thr.c */
  288         PROC_LOCK(p);
  289         p->p_flag |= P_HADTHREADS;
  290         newtd->td_sigmask = oldtd->td_sigmask; /* XXX dubious */
  291         thread_link(newtd, p);
  292         thread_lock(oldtd);
  293         /* let the scheduler know about these things. */
  294         sched_fork_thread(oldtd, newtd);
  295         TD_SET_CAN_RUN(newtd);
  296         thread_unlock(oldtd);
  297         PROC_UNLOCK(p);
  298 
  299 
  300         /* Delay putting it on the run queue until now. */
  301         if (!(flags & RFSTOPPED)) {
  302                 thread_lock(newtd);
  303                 sched_add(newtd, SRQ_BORING); 
  304                 thread_unlock(newtd);
  305         }
  306         if (newtdp)
  307                 *newtdp = newtd;
  308         return 0;
  309 }
  310 
  311 void
  312 kthread_exit(void)
  313 {
  314         struct proc *p;
  315 
  316         /* A module may be waiting for us to exit. */
  317         wakeup(curthread);
  318 
  319         /*
  320          * We could rely on thread_exit to call exit1() but
  321          * there is extra work that needs to be done
  322          */
  323         if (curthread->td_proc->p_numthreads == 1)
  324                 kproc_exit(0);  /* never returns */
  325 
  326         p = curthread->td_proc;
  327         PROC_LOCK(p);
  328         PROC_SLOCK(p);
  329         thread_exit();
  330 }
  331 
  332 /*
  333  * Advise a kernel process to suspend (or resume) in its main loop.
  334  * Participation is voluntary.
  335  */
  336 int
  337 kthread_suspend(struct thread *td, int timo)
  338 {
  339         if ((td->td_pflags & TDP_KTHREAD) == 0) {
  340                 return (EINVAL);
  341         }
  342         thread_lock(td);
  343         td->td_flags |= TDF_KTH_SUSP;
  344         thread_unlock(td);
  345         /*
  346          * If it's stopped for some other reason,
  347          * kick it to notice our request 
  348          * or we'll end up timing out
  349          */
  350         wakeup(td); /* traditional  place for kernel threads to sleep on */ /* XXX ?? */
  351         return (tsleep(&td->td_flags, PPAUSE | PDROP, "suspkt", timo));
  352 }
  353 
  354 /*
  355  * let the kthread it can keep going again.
  356  */
  357 int
  358 kthread_resume(struct thread *td)
  359 {
  360         if ((td->td_pflags & TDP_KTHREAD) == 0) {
  361                 return (EINVAL);
  362         }
  363         thread_lock(td);
  364         td->td_flags &= ~TDF_KTH_SUSP;
  365         thread_unlock(td);
  366         wakeup(&td->td_name);
  367         return (0);
  368 }
  369 
  370 /*
  371  * Used by the thread to poll as to whether it should yield/sleep
  372  * and notify the caller that is has happened.
  373  */
  374 void
  375 kthread_suspend_check(struct thread *td)
  376 {
  377         while (td->td_flags & TDF_KTH_SUSP) {
  378                 /*
  379                  * let the caller know we got the message then sleep
  380                  */
  381                 wakeup(&td->td_flags);
  382                 tsleep(&td->td_name, PPAUSE, "ktsusp", 0);
  383         }
  384 }
  385 
  386 int
  387 kproc_kthread_add(void (*func)(void *), void *arg,
  388             struct proc **procptr, struct thread **tdptr,
  389             int flags, int pages, char * procname, const char *fmt, ...) 
  390 {
  391         int error;
  392         va_list ap;
  393         char buf[100];
  394         struct thread *td;
  395 
  396         if (*procptr == 0) {
  397                 error = kproc_create(func, arg,
  398                         procptr, flags, pages, "%s", procname);
  399                 if (error)
  400                         return (error);
  401                 td = FIRST_THREAD_IN_PROC(*procptr);
  402                 if (tdptr)
  403                         *tdptr = td;
  404                 va_start(ap, fmt);
  405                 vsnprintf(td->td_name, sizeof(td->td_name), fmt, ap);
  406                 va_end(ap);
  407                 return (0); 
  408         }
  409         va_start(ap, fmt);
  410         vsnprintf(buf, sizeof(buf), fmt, ap);
  411         va_end(ap);
  412         error = kthread_add(func, arg, *procptr,
  413                     tdptr, flags, pages, "%s", buf);
  414         return (error);
  415 }

Cache object: 6e284a7bc96b611f2f9c29a88e52c3bb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.