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_condvar.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) 2000 Jake Burkholder <jake@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/6.4/sys/kern/kern_condvar.c 181936 2008-08-20 19:07:21Z jhb $");
   29 
   30 #include "opt_ktrace.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/lock.h>
   35 #include <sys/mutex.h>
   36 #include <sys/proc.h>
   37 #include <sys/kernel.h>
   38 #include <sys/ktr.h>
   39 #include <sys/condvar.h>
   40 #include <sys/sched.h>
   41 #include <sys/signalvar.h>
   42 #include <sys/sleepqueue.h>
   43 #include <sys/resourcevar.h>
   44 #ifdef KTRACE
   45 #include <sys/uio.h>
   46 #include <sys/ktrace.h>
   47 #endif
   48 
   49 /*
   50  * Common sanity checks for cv_wait* functions.
   51  */
   52 #define CV_ASSERT(cvp, mp, td) do {                                     \
   53         KASSERT((td) != NULL, ("%s: curthread NULL", __func__));        \
   54         KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__));  \
   55         KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__));             \
   56         KASSERT((mp) != NULL, ("%s: mp NULL", __func__));               \
   57         mtx_assert((mp), MA_OWNED | MA_NOTRECURSED);                    \
   58 } while (0)
   59 
   60 /*
   61  * Initialize a condition variable.  Must be called before use.
   62  */
   63 void
   64 cv_init(struct cv *cvp, const char *desc)
   65 {
   66 
   67         cvp->cv_description = desc;
   68         cvp->cv_waiters = 0;
   69 }
   70 
   71 /*
   72  * Destroy a condition variable.  The condition variable must be re-initialized
   73  * in order to be re-used.
   74  */
   75 void
   76 cv_destroy(struct cv *cvp)
   77 {
   78 #ifdef INVARIANTS
   79         struct sleepqueue *sq;
   80 
   81         sleepq_lock(cvp);
   82         sq = sleepq_lookup(cvp);
   83         sleepq_release(cvp);
   84         KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
   85 #endif
   86 }
   87 
   88 /*
   89  * Wait on a condition variable.  The current thread is placed on the condition
   90  * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
   91  * condition variable will resume the thread.  The mutex is released before
   92  * sleeping and will be held on return.  It is recommended that the mutex be
   93  * held when cv_signal or cv_broadcast are called.
   94  */
   95 void
   96 cv_wait(struct cv *cvp, struct mtx *mp)
   97 {
   98         struct thread *td;
   99         WITNESS_SAVE_DECL(mp);
  100 
  101         td = curthread;
  102 #ifdef KTRACE
  103         if (KTRPOINT(td, KTR_CSW))
  104                 ktrcsw(1, 0);
  105 #endif
  106         CV_ASSERT(cvp, mp, td);
  107         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
  108             "Waiting on \"%s\"", cvp->cv_description);
  109         WITNESS_SAVE(&mp->mtx_object, mp);
  110 
  111         if (cold || panicstr) {
  112                 /*
  113                  * During autoconfiguration, just give interrupts
  114                  * a chance, then just return.  Don't run any other
  115                  * thread or panic below, in case this is the idle
  116                  * process and already asleep.
  117                  */
  118                 return;
  119         }
  120 
  121         sleepq_lock(cvp);
  122 
  123         cvp->cv_waiters++;
  124         DROP_GIANT();
  125         mtx_unlock(mp);
  126 
  127         sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR,
  128             0);
  129         sleepq_wait(cvp);
  130 
  131 #ifdef KTRACE
  132         if (KTRPOINT(td, KTR_CSW))
  133                 ktrcsw(0, 0);
  134 #endif
  135         PICKUP_GIANT();
  136         mtx_lock(mp);
  137         WITNESS_RESTORE(&mp->mtx_object, mp);
  138 }
  139 
  140 /*
  141  * Wait on a condition variable, allowing interruption by signals.  Return 0 if
  142  * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
  143  * a signal was caught.  If ERESTART is returned the system call should be
  144  * restarted if possible.
  145  */
  146 int
  147 cv_wait_sig(struct cv *cvp, struct mtx *mp)
  148 {
  149         struct thread *td;
  150         struct proc *p;
  151         int rval;
  152         WITNESS_SAVE_DECL(mp);
  153 
  154         td = curthread;
  155         p = td->td_proc;
  156 #ifdef KTRACE
  157         if (KTRPOINT(td, KTR_CSW))
  158                 ktrcsw(1, 0);
  159 #endif
  160         CV_ASSERT(cvp, mp, td);
  161         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
  162             "Waiting on \"%s\"", cvp->cv_description);
  163         WITNESS_SAVE(&mp->mtx_object, mp);
  164 
  165         if (cold || panicstr) {
  166                 /*
  167                  * After a panic, or during autoconfiguration, just give
  168                  * interrupts a chance, then just return; don't run any other
  169                  * procs or panic below, in case this is the idle process and
  170                  * already asleep.
  171                  */
  172                 return (0);
  173         }
  174 
  175         sleepq_lock(cvp);
  176 
  177         cvp->cv_waiters++;
  178         DROP_GIANT();
  179         mtx_unlock(mp);
  180 
  181         sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR |
  182             SLEEPQ_INTERRUPTIBLE, 0);
  183         rval = sleepq_wait_sig(cvp);
  184 
  185 #ifdef KTRACE
  186         if (KTRPOINT(td, KTR_CSW))
  187                 ktrcsw(0, 0);
  188 #endif
  189         PICKUP_GIANT();
  190         mtx_lock(mp);
  191         WITNESS_RESTORE(&mp->mtx_object, mp);
  192 
  193         return (rval);
  194 }
  195 
  196 /*
  197  * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
  198  * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
  199  * expires.
  200  */
  201 int
  202 cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
  203 {
  204         struct thread *td;
  205         int rval;
  206         WITNESS_SAVE_DECL(mp);
  207 
  208         td = curthread;
  209         rval = 0;
  210 #ifdef KTRACE
  211         if (KTRPOINT(td, KTR_CSW))
  212                 ktrcsw(1, 0);
  213 #endif
  214         CV_ASSERT(cvp, mp, td);
  215         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
  216             "Waiting on \"%s\"", cvp->cv_description);
  217         WITNESS_SAVE(&mp->mtx_object, mp);
  218 
  219         if (cold || panicstr) {
  220                 /*
  221                  * After a panic, or during autoconfiguration, just give
  222                  * interrupts a chance, then just return; don't run any other
  223                  * thread or panic below, in case this is the idle process and
  224                  * already asleep.
  225                  */
  226                 return 0;
  227         }
  228 
  229         sleepq_lock(cvp);
  230 
  231         cvp->cv_waiters++;
  232         DROP_GIANT();
  233         mtx_unlock(mp);
  234 
  235         sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR,
  236             0);
  237         sleepq_set_timeout(cvp, timo);
  238         rval = sleepq_timedwait(cvp);
  239 
  240 #ifdef KTRACE
  241         if (KTRPOINT(td, KTR_CSW))
  242                 ktrcsw(0, 0);
  243 #endif
  244         PICKUP_GIANT();
  245         mtx_lock(mp);
  246         WITNESS_RESTORE(&mp->mtx_object, mp);
  247 
  248         return (rval);
  249 }
  250 
  251 /*
  252  * Wait on a condition variable for at most timo/hz seconds, allowing
  253  * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
  254  * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
  255  * a signal was caught.
  256  */
  257 int
  258 cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
  259 {
  260         struct thread *td;
  261         struct proc *p;
  262         int rval;
  263         WITNESS_SAVE_DECL(mp);
  264 
  265         td = curthread;
  266         p = td->td_proc;
  267         rval = 0;
  268 #ifdef KTRACE
  269         if (KTRPOINT(td, KTR_CSW))
  270                 ktrcsw(1, 0);
  271 #endif
  272         CV_ASSERT(cvp, mp, td);
  273         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
  274             "Waiting on \"%s\"", cvp->cv_description);
  275         WITNESS_SAVE(&mp->mtx_object, mp);
  276 
  277         if (cold || panicstr) {
  278                 /*
  279                  * After a panic, or during autoconfiguration, just give
  280                  * interrupts a chance, then just return; don't run any other
  281                  * thread or panic below, in case this is the idle process and
  282                  * already asleep.
  283                  */
  284                 return 0;
  285         }
  286 
  287         sleepq_lock(cvp);
  288 
  289         cvp->cv_waiters++;
  290         DROP_GIANT();
  291         mtx_unlock(mp);
  292 
  293         sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR |
  294             SLEEPQ_INTERRUPTIBLE, 0);
  295         sleepq_set_timeout(cvp, timo);
  296         rval = sleepq_timedwait_sig(cvp);
  297 
  298 #ifdef KTRACE
  299         if (KTRPOINT(td, KTR_CSW))
  300                 ktrcsw(0, 0);
  301 #endif
  302         PICKUP_GIANT();
  303         mtx_lock(mp);
  304         WITNESS_RESTORE(&mp->mtx_object, mp);
  305 
  306         return (rval);
  307 }
  308 
  309 /*
  310  * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
  311  * the swapper if the process is not in memory, so that it can bring the
  312  * sleeping process in.  Note that this may also result in additional threads
  313  * being made runnable.  Should be called with the same mutex as was passed to
  314  * cv_wait held.
  315  */
  316 void
  317 cv_signal(struct cv *cvp)
  318 {
  319 
  320         sleepq_lock(cvp);
  321         if (cvp->cv_waiters > 0) {
  322                 cvp->cv_waiters--;
  323                 sleepq_signal(cvp, SLEEPQ_CONDVAR, -1, 0);
  324         } else
  325                 sleepq_release(cvp);
  326 }
  327 
  328 /*
  329  * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
  330  * Should be called with the same mutex as was passed to cv_wait held.
  331  */
  332 void
  333 cv_broadcastpri(struct cv *cvp, int pri)
  334 {
  335 
  336         sleepq_lock(cvp);
  337         if (cvp->cv_waiters > 0) {
  338                 cvp->cv_waiters = 0;
  339                 sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0);
  340         } else
  341                 sleepq_release(cvp);
  342 }

Cache object: 620d027d718d12581d2f236a08653e1e


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