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_synch.c

Version: -  FREEBSD  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  cheribsd  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1  -  FREEBSD-LIBC  -  FREEBSD8-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: kern_synch.c,v 1.87 2008/09/10 12:30:40 blambert Exp $        */
    2 /*      $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */
    3 
    4 /*
    5  * Copyright (c) 1982, 1986, 1990, 1991, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  * (c) UNIX System Laboratories, Inc.
    8  * All or some portions of this file are derived from material licensed
    9  * to the University of California by American Telephone and Telegraph
   10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   11  * the permission of UNIX System Laboratories, Inc.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  *
   37  *      @(#)kern_synch.c        8.6 (Berkeley) 1/21/94
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/proc.h>
   43 #include <sys/kernel.h>
   44 #include <sys/buf.h>
   45 #include <sys/signalvar.h>
   46 #include <sys/resourcevar.h>
   47 #include <uvm/uvm_extern.h>
   48 #include <sys/sched.h>
   49 #include <sys/timeout.h>
   50 #include <sys/mount.h>
   51 #include <sys/syscallargs.h>
   52 #include <sys/pool.h>
   53 
   54 #include <machine/spinlock.h>
   55 
   56 #ifdef KTRACE
   57 #include <sys/ktrace.h>
   58 #endif
   59 
   60 void updatepri(struct proc *);
   61 void endtsleep(void *);
   62 
   63 /*
   64  * We're only looking at 7 bits of the address; everything is
   65  * aligned to 4, lots of things are aligned to greater powers
   66  * of 2.  Shift right by 8, i.e. drop the bottom 256 worth.
   67  */
   68 #define TABLESIZE       128
   69 #define LOOKUP(x)       (((long)(x) >> 8) & (TABLESIZE - 1))
   70 TAILQ_HEAD(slpque,proc) slpque[TABLESIZE];
   71 
   72 void
   73 sleep_queue_init(void)
   74 {
   75         int i;
   76 
   77         for (i = 0; i < TABLESIZE; i++)
   78                 TAILQ_INIT(&slpque[i]);
   79 }
   80 
   81 
   82 /*
   83  * During autoconfiguration or after a panic, a sleep will simply
   84  * lower the priority briefly to allow interrupts, then return.
   85  * The priority to be used (safepri) is machine-dependent, thus this
   86  * value is initialized and maintained in the machine-dependent layers.
   87  * This priority will typically be 0, or the lowest priority
   88  * that is safe for use on the interrupt stack; it can be made
   89  * higher to block network software interrupts after panics.
   90  */
   91 int safepri;
   92 
   93 /*
   94  * General sleep call.  Suspends the current process until a wakeup is
   95  * performed on the specified identifier.  The process will then be made
   96  * runnable with the specified priority.  Sleeps at most timo/hz seconds
   97  * (0 means no timeout).  If pri includes PCATCH flag, signals are checked
   98  * before and after sleeping, else signals are not checked.  Returns 0 if
   99  * awakened, EWOULDBLOCK if the timeout expires.  If PCATCH is set and a
  100  * signal needs to be delivered, ERESTART is returned if the current system
  101  * call should be restarted if possible, and EINTR is returned if the system
  102  * call should be interrupted by the signal (return EINTR).
  103  */
  104 int
  105 tsleep(void *ident, int priority, const char *wmesg, int timo)
  106 {
  107         struct sleep_state sls;
  108         int error, error1;
  109 
  110         if (cold || panicstr) {
  111                 int s;
  112                 /*
  113                  * After a panic, or during autoconfiguration,
  114                  * just give interrupts a chance, then just return;
  115                  * don't run any other procs or panic below,
  116                  * in case this is the idle process and already asleep.
  117                  */
  118                 s = splhigh();
  119                 splx(safepri);
  120                 splx(s);
  121                 return (0);
  122         }
  123 
  124         sleep_setup(&sls, ident, priority, wmesg);
  125         sleep_setup_timeout(&sls, timo);
  126         sleep_setup_signal(&sls, priority);
  127 
  128         sleep_finish(&sls, 1);
  129         error1 = sleep_finish_timeout(&sls);
  130         error = sleep_finish_signal(&sls);
  131 
  132         /* Signal errors are higher priority than timeouts. */
  133         if (error == 0 && error1 != 0)
  134                 error = error1;
  135 
  136         return (error);
  137 }
  138 
  139 /*
  140  * Same as tsleep, but if we have a mutex provided, then once we've 
  141  * entered the sleep queue we drop the mutex. After sleeping we re-lock.
  142  */
  143 int
  144 msleep(void *ident, struct mutex *mtx,  int priority, const char *wmesg, int timo)
  145 {
  146         struct sleep_state sls;
  147         int error, error1, spl;
  148 
  149         sleep_setup(&sls, ident, priority, wmesg);
  150         sleep_setup_timeout(&sls, timo);
  151         sleep_setup_signal(&sls, priority);
  152 
  153         if (mtx) {
  154                 /* XXX - We need to make sure that the mutex doesn't
  155                  * unblock splsched. This can be made a bit more 
  156                  * correct when the sched_lock is a mutex.
  157                  */
  158                 spl = MUTEX_OLDIPL(mtx);
  159                 MUTEX_OLDIPL(mtx) = splsched();
  160                 mtx_leave(mtx);
  161         }
  162 
  163         sleep_finish(&sls, 1);
  164         error1 = sleep_finish_timeout(&sls);
  165         error = sleep_finish_signal(&sls);
  166 
  167         if (mtx && (priority & PNORELOCK) == 0) {
  168                 mtx_enter(mtx);
  169                 MUTEX_OLDIPL(mtx) = spl; /* put the ipl back */
  170         }
  171         /* Signal errors are higher priority than timeouts. */
  172         if (error == 0 && error1 != 0)
  173                 error = error1;
  174 
  175         return (error);
  176 }
  177 
  178 void
  179 sleep_setup(struct sleep_state *sls, void *ident, int prio, const char *wmesg)
  180 {
  181         struct proc *p = curproc;
  182 
  183 #ifdef DIAGNOSTIC
  184         if (ident == NULL)
  185                 panic("tsleep: no ident");
  186         if (p->p_stat != SONPROC)
  187                 panic("tsleep: not SONPROC");
  188 #endif
  189 
  190 #ifdef KTRACE
  191         if (KTRPOINT(p, KTR_CSW))
  192                 ktrcsw(p, 1, 0);
  193 #endif
  194 
  195         sls->sls_catch = 0;
  196         sls->sls_do_sleep = 1;
  197         sls->sls_sig = 1;
  198 
  199         SCHED_LOCK(sls->sls_s);
  200 
  201         p->p_wchan = ident;
  202         p->p_wmesg = wmesg;
  203         p->p_slptime = 0;
  204         p->p_priority = prio & PRIMASK;
  205         TAILQ_INSERT_TAIL(&slpque[LOOKUP(ident)], p, p_runq);
  206 }
  207 
  208 void
  209 sleep_finish(struct sleep_state *sls, int do_sleep)
  210 {
  211         struct proc *p = curproc;
  212 
  213         if (sls->sls_do_sleep && do_sleep) {
  214                 p->p_stat = SSLEEP;
  215                 p->p_stats->p_ru.ru_nvcsw++;
  216                 SCHED_ASSERT_LOCKED();
  217                 mi_switch();
  218         } else if (!do_sleep) {
  219                 unsleep(p);
  220         }
  221 
  222 #ifdef DIAGNOSTIC
  223         if (p->p_stat != SONPROC)
  224                 panic("sleep_finish !SONPROC");
  225 #endif
  226 
  227         p->p_cpu->ci_schedstate.spc_curpriority = p->p_usrpri;
  228         SCHED_UNLOCK(sls->sls_s);
  229 
  230         /*
  231          * Even though this belongs to the signal handling part of sleep,
  232          * we need to clear it before the ktrace.
  233          */
  234         atomic_clearbits_int(&p->p_flag, P_SINTR);
  235 
  236 #ifdef KTRACE
  237         if (KTRPOINT(p, KTR_CSW))
  238                 ktrcsw(p, 0, 0);
  239 #endif
  240 }
  241 
  242 void
  243 sleep_setup_timeout(struct sleep_state *sls, int timo)
  244 {
  245         if (timo)
  246                 timeout_add(&curproc->p_sleep_to, timo);
  247 }
  248 
  249 int
  250 sleep_finish_timeout(struct sleep_state *sls)
  251 {
  252         struct proc *p = curproc;
  253 
  254         if (p->p_flag & P_TIMEOUT) {
  255                 atomic_clearbits_int(&p->p_flag, P_TIMEOUT);
  256                 return (EWOULDBLOCK);
  257         } else if (timeout_pending(&p->p_sleep_to)) {
  258                 timeout_del(&p->p_sleep_to);
  259         }
  260 
  261         return (0);
  262 }
  263 
  264 void
  265 sleep_setup_signal(struct sleep_state *sls, int prio)
  266 {
  267         struct proc *p = curproc;
  268 
  269         if ((sls->sls_catch = (prio & PCATCH)) == 0)
  270                 return;
  271 
  272         /*
  273          * We put ourselves on the sleep queue and start our timeout
  274          * before calling CURSIG, as we could stop there, and a wakeup
  275          * or a SIGCONT (or both) could occur while we were stopped.
  276          * A SIGCONT would cause us to be marked as SSLEEP
  277          * without resuming us, thus we must be ready for sleep
  278          * when CURSIG is called.  If the wakeup happens while we're
  279          * stopped, p->p_wchan will be 0 upon return from CURSIG.
  280          */
  281         atomic_setbits_int(&p->p_flag, P_SINTR);
  282         if ((sls->sls_sig = CURSIG(p)) != 0) {
  283                 if (p->p_wchan)
  284                         unsleep(p);
  285                 p->p_stat = SONPROC;
  286                 sls->sls_do_sleep = 0;
  287         } else if (p->p_wchan == 0) {
  288                 sls->sls_catch = 0;
  289                 sls->sls_do_sleep = 0;
  290         }
  291 }
  292 
  293 int
  294 sleep_finish_signal(struct sleep_state *sls)
  295 {
  296         struct proc *p = curproc;
  297 
  298         if (sls->sls_catch != 0) {
  299                 if (sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0) {
  300                         if (p->p_sigacts->ps_sigintr & sigmask(sls->sls_sig))
  301                                 return (EINTR);
  302                         return (ERESTART);
  303                 }
  304         }
  305 
  306         return (0);
  307 }
  308 
  309 /*
  310  * Implement timeout for tsleep.
  311  * If process hasn't been awakened (wchan non-zero),
  312  * set timeout flag and undo the sleep.  If proc
  313  * is stopped, just unsleep so it will remain stopped.
  314  */
  315 void
  316 endtsleep(void *arg)
  317 {
  318         struct proc *p = arg;
  319         int s;
  320 
  321         SCHED_LOCK(s);
  322         if (p->p_wchan) {
  323                 if (p->p_stat == SSLEEP)
  324                         setrunnable(p);
  325                 else
  326                         unsleep(p);
  327                 atomic_setbits_int(&p->p_flag, P_TIMEOUT);
  328         }
  329         SCHED_UNLOCK(s);
  330 }
  331 
  332 /*
  333  * Remove a process from its wait queue
  334  */
  335 void
  336 unsleep(struct proc *p)
  337 {
  338         if (p->p_wchan) {
  339                 TAILQ_REMOVE(&slpque[LOOKUP(p->p_wchan)], p, p_runq);
  340                 p->p_wchan = NULL;
  341         }
  342 }
  343 
  344 /*
  345  * Make a number of processes sleeping on the specified identifier runnable.
  346  */
  347 void
  348 wakeup_n(void *ident, int n)
  349 {
  350         struct slpque *qp;
  351         struct proc *p;
  352         struct proc *pnext;
  353         int s;
  354 
  355         SCHED_LOCK(s);
  356         qp = &slpque[LOOKUP(ident)];
  357         for (p = TAILQ_FIRST(qp); p != NULL && n != 0; p = pnext) {
  358                 pnext = TAILQ_NEXT(p, p_runq);
  359 #ifdef DIAGNOSTIC
  360                 if (p->p_stat != SSLEEP && p->p_stat != SSTOP)
  361                         panic("wakeup: p_stat is %d", (int)p->p_stat);
  362 #endif
  363                 if (p->p_wchan == ident) {
  364                         --n;
  365                         p->p_wchan = 0;
  366                         TAILQ_REMOVE(qp, p, p_runq);
  367                         if (p->p_stat == SSLEEP) {
  368                                 /* OPTIMIZED EXPANSION OF setrunnable(p); */
  369                                 if (p->p_slptime > 1)
  370                                         updatepri(p);
  371                                 p->p_slptime = 0;
  372                                 p->p_stat = SRUN;
  373 
  374                                 /*
  375                                  * Since curpriority is a user priority,
  376                                  * p->p_priority is always better than
  377                                  * curpriority on the last CPU on
  378                                  * which it ran.
  379                                  *
  380                                  * XXXSMP See affinity comment in
  381                                  * resched_proc().
  382                                  */
  383                                 setrunqueue(p);
  384                                 KASSERT(p->p_cpu != NULL);
  385                                 need_resched(p->p_cpu);
  386                                 /* END INLINE EXPANSION */
  387 
  388                         }
  389                 }
  390         }
  391         SCHED_UNLOCK(s);
  392 }
  393 
  394 /*
  395  * Make all processes sleeping on the specified identifier runnable.
  396  */
  397 void
  398 wakeup(void *chan)
  399 {
  400         wakeup_n(chan, -1);
  401 }
  402 
  403 int
  404 sys_sched_yield(struct proc *p, void *v, register_t *retval)
  405 {
  406         yield();
  407         return (0);
  408 }
  409 
  410 #ifdef RTHREADS
  411 
  412 int
  413 sys_thrsleep(struct proc *p, void *v, register_t *revtal)
  414 {
  415         struct sys_thrsleep_args *uap = v;
  416         long ident = (long)SCARG(uap, ident);
  417         int timo = SCARG(uap, timeout);
  418         _spinlock_lock_t *lock = SCARG(uap, lock);
  419         _spinlock_lock_t unlocked = _SPINLOCK_UNLOCKED;
  420         int error;
  421 
  422         p->p_thrslpid = ident;
  423 
  424         if (lock)
  425                 copyout(&unlocked, lock, sizeof(unlocked));
  426         if (hz > 1000)
  427                 timo = timo * (hz / 1000);
  428         else
  429                 timo = timo / (1000 / hz);
  430         if (timo < 0)
  431                 timo = 0;
  432         error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep", timo);
  433 
  434         if (error == ERESTART)
  435                 error = EINTR;
  436 
  437         return (error);
  438 
  439 }
  440 
  441 int
  442 sys_thrwakeup(struct proc *p, void *v, register_t *retval)
  443 {
  444         struct sys_thrwakeup_args *uap = v;
  445         long ident = (long)SCARG(uap, ident);
  446         int n = SCARG(uap, n);
  447         struct proc *q;
  448         int found = 0;
  449 
  450         TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) {
  451                 if (q->p_thrslpid == ident) {
  452                         wakeup_one(&q->p_thrslpid);
  453                         q->p_thrslpid = 0;
  454                         if (++found == n)
  455                                 return (0);
  456                 }
  457         }
  458         if (!found)
  459                 return (ESRCH);
  460 
  461         return (0);
  462 }
  463 #endif

Cache object: b6ade72a27014a27c91fc781a0a7771f


[ 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.