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.3/sys/kern/kern_condvar.c 173886 2007-11-24 19:45:58Z cvs2svn $");
   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, cvp->cv_description, SLEEPQ_CONDVAR, 0);
  128         sleepq_wait(cvp);
  129 
  130 #ifdef KTRACE
  131         if (KTRPOINT(td, KTR_CSW))
  132                 ktrcsw(0, 0);
  133 #endif
  134         PICKUP_GIANT();
  135         mtx_lock(mp);
  136         WITNESS_RESTORE(&mp->mtx_object, mp);
  137 }
  138 
  139 /*
  140  * Wait on a condition variable, allowing interruption by signals.  Return 0 if
  141  * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
  142  * a signal was caught.  If ERESTART is returned the system call should be
  143  * restarted if possible.
  144  */
  145 int
  146 cv_wait_sig(struct cv *cvp, struct mtx *mp)
  147 {
  148         struct thread *td;
  149         struct proc *p;
  150         int rval;
  151         WITNESS_SAVE_DECL(mp);
  152 
  153         td = curthread;
  154         p = td->td_proc;
  155 #ifdef KTRACE
  156         if (KTRPOINT(td, KTR_CSW))
  157                 ktrcsw(1, 0);
  158 #endif
  159         CV_ASSERT(cvp, mp, td);
  160         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
  161             "Waiting on \"%s\"", cvp->cv_description);
  162         WITNESS_SAVE(&mp->mtx_object, mp);
  163 
  164         if (cold || panicstr) {
  165                 /*
  166                  * After a panic, or during autoconfiguration, just give
  167                  * interrupts a chance, then just return; don't run any other
  168                  * procs or panic below, in case this is the idle process and
  169                  * already asleep.
  170                  */
  171                 return (0);
  172         }
  173 
  174         sleepq_lock(cvp);
  175 
  176         cvp->cv_waiters++;
  177         DROP_GIANT();
  178         mtx_unlock(mp);
  179 
  180         sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR |
  181             SLEEPQ_INTERRUPTIBLE, 0);
  182         rval = sleepq_wait_sig(cvp);
  183 
  184 #ifdef KTRACE
  185         if (KTRPOINT(td, KTR_CSW))
  186                 ktrcsw(0, 0);
  187 #endif
  188         PICKUP_GIANT();
  189         mtx_lock(mp);
  190         WITNESS_RESTORE(&mp->mtx_object, mp);
  191 
  192         return (rval);
  193 }
  194 
  195 /*
  196  * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
  197  * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
  198  * expires.
  199  */
  200 int
  201 cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
  202 {
  203         struct thread *td;
  204         int rval;
  205         WITNESS_SAVE_DECL(mp);
  206 
  207         td = curthread;
  208         rval = 0;
  209 #ifdef KTRACE
  210         if (KTRPOINT(td, KTR_CSW))
  211                 ktrcsw(1, 0);
  212 #endif
  213         CV_ASSERT(cvp, mp, td);
  214         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
  215             "Waiting on \"%s\"", cvp->cv_description);
  216         WITNESS_SAVE(&mp->mtx_object, mp);
  217 
  218         if (cold || panicstr) {
  219                 /*
  220                  * After a panic, or during autoconfiguration, just give
  221                  * interrupts a chance, then just return; don't run any other
  222                  * thread or panic below, in case this is the idle process and
  223                  * already asleep.
  224                  */
  225                 return 0;
  226         }
  227 
  228         sleepq_lock(cvp);
  229 
  230         cvp->cv_waiters++;
  231         DROP_GIANT();
  232         mtx_unlock(mp);
  233 
  234         sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR, 0);
  235         sleepq_set_timeout(cvp, timo);
  236         rval = sleepq_timedwait(cvp);
  237 
  238 #ifdef KTRACE
  239         if (KTRPOINT(td, KTR_CSW))
  240                 ktrcsw(0, 0);
  241 #endif
  242         PICKUP_GIANT();
  243         mtx_lock(mp);
  244         WITNESS_RESTORE(&mp->mtx_object, mp);
  245 
  246         return (rval);
  247 }
  248 
  249 /*
  250  * Wait on a condition variable for at most timo/hz seconds, allowing
  251  * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
  252  * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
  253  * a signal was caught.
  254  */
  255 int
  256 cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
  257 {
  258         struct thread *td;
  259         struct proc *p;
  260         int rval;
  261         WITNESS_SAVE_DECL(mp);
  262 
  263         td = curthread;
  264         p = td->td_proc;
  265         rval = 0;
  266 #ifdef KTRACE
  267         if (KTRPOINT(td, KTR_CSW))
  268                 ktrcsw(1, 0);
  269 #endif
  270         CV_ASSERT(cvp, mp, td);
  271         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
  272             "Waiting on \"%s\"", cvp->cv_description);
  273         WITNESS_SAVE(&mp->mtx_object, mp);
  274 
  275         if (cold || panicstr) {
  276                 /*
  277                  * After a panic, or during autoconfiguration, just give
  278                  * interrupts a chance, then just return; don't run any other
  279                  * thread or panic below, in case this is the idle process and
  280                  * already asleep.
  281                  */
  282                 return 0;
  283         }
  284 
  285         sleepq_lock(cvp);
  286 
  287         cvp->cv_waiters++;
  288         DROP_GIANT();
  289         mtx_unlock(mp);
  290 
  291         sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR |
  292             SLEEPQ_INTERRUPTIBLE, 0);
  293         sleepq_set_timeout(cvp, timo);
  294         rval = sleepq_timedwait_sig(cvp);
  295 
  296 #ifdef KTRACE
  297         if (KTRPOINT(td, KTR_CSW))
  298                 ktrcsw(0, 0);
  299 #endif
  300         PICKUP_GIANT();
  301         mtx_lock(mp);
  302         WITNESS_RESTORE(&mp->mtx_object, mp);
  303 
  304         return (rval);
  305 }
  306 
  307 /*
  308  * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
  309  * the swapper if the process is not in memory, so that it can bring the
  310  * sleeping process in.  Note that this may also result in additional threads
  311  * being made runnable.  Should be called with the same mutex as was passed to
  312  * cv_wait held.
  313  */
  314 void
  315 cv_signal(struct cv *cvp)
  316 {
  317 
  318         sleepq_lock(cvp);
  319         if (cvp->cv_waiters > 0) {
  320                 cvp->cv_waiters--;
  321                 sleepq_signal(cvp, SLEEPQ_CONDVAR, -1, 0);
  322         } else
  323                 sleepq_release(cvp);
  324 }
  325 
  326 /*
  327  * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
  328  * Should be called with the same mutex as was passed to cv_wait held.
  329  */
  330 void
  331 cv_broadcastpri(struct cv *cvp, int pri)
  332 {
  333 
  334         sleepq_lock(cvp);
  335         if (cvp->cv_waiters > 0) {
  336                 cvp->cv_waiters = 0;
  337                 sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0);
  338         } else
  339                 sleepq_release(cvp);
  340 }

Cache object: 7098d60681cacb70bf7f6184211176ee


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