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/5.3/sys/kern/kern_condvar.c 136588 2004-10-16 08:43:07Z 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         sq = sleepq_lookup(cvp);
   82         sleepq_release(cvp);
   83         KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
   84 #endif
   85 }
   86 
   87 /*
   88  * Wait on a condition variable.  The current thread is placed on the condition
   89  * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
   90  * condition variable will resume the thread.  The mutex is released before
   91  * sleeping and will be held on return.  It is recommended that the mutex be
   92  * held when cv_signal or cv_broadcast are called.
   93  */
   94 void
   95 cv_wait(struct cv *cvp, struct mtx *mp)
   96 {
   97         struct sleepqueue *sq;
   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         sq = sleepq_lookup(cvp);
  122 
  123         cvp->cv_waiters++;
  124         DROP_GIANT();
  125         mtx_unlock(mp);
  126 
  127         sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
  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 sleepqueue *sq;
  149         struct thread *td;
  150         struct proc *p;
  151         int rval, sig;
  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         sq = sleepq_lookup(cvp);
  176 
  177         /*
  178          * Don't bother sleeping if we are exiting and not the exiting
  179          * thread or if our thread is marked as interrupted.
  180          */
  181         mtx_lock_spin(&sched_lock);
  182         rval = thread_sleep_check(td);
  183         mtx_unlock_spin(&sched_lock);
  184         if (rval != 0) {
  185                 sleepq_release(cvp);
  186                 return (rval);
  187         }
  188 
  189         cvp->cv_waiters++;
  190         DROP_GIANT();
  191         mtx_unlock(mp);
  192 
  193         sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR |
  194             SLEEPQ_INTERRUPTIBLE);
  195         sig = sleepq_catch_signals(cvp);
  196         rval = sleepq_wait_sig(cvp);
  197         if (rval == 0)
  198                 rval = sleepq_calc_signal_retval(sig);
  199 
  200 #ifdef KTRACE
  201         if (KTRPOINT(td, KTR_CSW))
  202                 ktrcsw(0, 0);
  203 #endif
  204         PICKUP_GIANT();
  205         mtx_lock(mp);
  206         WITNESS_RESTORE(&mp->mtx_object, mp);
  207 
  208         return (rval);
  209 }
  210 
  211 /*
  212  * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
  213  * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
  214  * expires.
  215  */
  216 int
  217 cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
  218 {
  219         struct sleepqueue *sq;
  220         struct thread *td;
  221         int rval;
  222         WITNESS_SAVE_DECL(mp);
  223 
  224         td = curthread;
  225         rval = 0;
  226 #ifdef KTRACE
  227         if (KTRPOINT(td, KTR_CSW))
  228                 ktrcsw(1, 0);
  229 #endif
  230         CV_ASSERT(cvp, mp, td);
  231         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
  232             "Waiting on \"%s\"", cvp->cv_description);
  233         WITNESS_SAVE(&mp->mtx_object, mp);
  234 
  235         if (cold || panicstr) {
  236                 /*
  237                  * After a panic, or during autoconfiguration, just give
  238                  * interrupts a chance, then just return; don't run any other
  239                  * thread or panic below, in case this is the idle process and
  240                  * already asleep.
  241                  */
  242                 return 0;
  243         }
  244 
  245         sq = sleepq_lookup(cvp);
  246 
  247         cvp->cv_waiters++;
  248         DROP_GIANT();
  249         mtx_unlock(mp);
  250 
  251         sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
  252         sleepq_set_timeout(cvp, timo);
  253         rval = sleepq_timedwait(cvp);
  254 
  255 #ifdef KTRACE
  256         if (KTRPOINT(td, KTR_CSW))
  257                 ktrcsw(0, 0);
  258 #endif
  259         PICKUP_GIANT();
  260         mtx_lock(mp);
  261         WITNESS_RESTORE(&mp->mtx_object, mp);
  262 
  263         return (rval);
  264 }
  265 
  266 /*
  267  * Wait on a condition variable for at most timo/hz seconds, allowing
  268  * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
  269  * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
  270  * a signal was caught.
  271  */
  272 int
  273 cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
  274 {
  275         struct sleepqueue *sq;
  276         struct thread *td;
  277         struct proc *p;
  278         int rval;
  279         int sig;
  280         WITNESS_SAVE_DECL(mp);
  281 
  282         td = curthread;
  283         p = td->td_proc;
  284         rval = 0;
  285 #ifdef KTRACE
  286         if (KTRPOINT(td, KTR_CSW))
  287                 ktrcsw(1, 0);
  288 #endif
  289         CV_ASSERT(cvp, mp, td);
  290         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
  291             "Waiting on \"%s\"", cvp->cv_description);
  292         WITNESS_SAVE(&mp->mtx_object, mp);
  293 
  294         if (cold || panicstr) {
  295                 /*
  296                  * After a panic, or during autoconfiguration, just give
  297                  * interrupts a chance, then just return; don't run any other
  298                  * thread or panic below, in case this is the idle process and
  299                  * already asleep.
  300                  */
  301                 return 0;
  302         }
  303 
  304         sq = sleepq_lookup(cvp);
  305 
  306         /*
  307          * Don't bother sleeping if we are exiting and not the exiting
  308          * thread or if our thread is marked as interrupted.
  309          */
  310         mtx_lock_spin(&sched_lock);
  311         rval = thread_sleep_check(td);
  312         mtx_unlock_spin(&sched_lock);
  313         if (rval != 0) {
  314                 sleepq_release(cvp);
  315                 return (rval);
  316         }
  317 
  318         cvp->cv_waiters++;
  319         DROP_GIANT();
  320         mtx_unlock(mp);
  321 
  322         sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR |
  323             SLEEPQ_INTERRUPTIBLE);
  324         sleepq_set_timeout(cvp, timo);
  325         sig = sleepq_catch_signals(cvp);
  326         rval = sleepq_timedwait_sig(cvp, sig != 0);
  327         if (rval == 0)
  328                 rval = sleepq_calc_signal_retval(sig);
  329 
  330 #ifdef KTRACE
  331         if (KTRPOINT(td, KTR_CSW))
  332                 ktrcsw(0, 0);
  333 #endif
  334         PICKUP_GIANT();
  335         mtx_lock(mp);
  336         WITNESS_RESTORE(&mp->mtx_object, mp);
  337 
  338         return (rval);
  339 }
  340 
  341 /*
  342  * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
  343  * the swapper if the process is not in memory, so that it can bring the
  344  * sleeping process in.  Note that this may also result in additional threads
  345  * being made runnable.  Should be called with the same mutex as was passed to
  346  * cv_wait held.
  347  */
  348 void
  349 cv_signal(struct cv *cvp)
  350 {
  351 
  352         if (cvp->cv_waiters > 0) {
  353                 cvp->cv_waiters--;
  354                 sleepq_signal(cvp, SLEEPQ_CONDVAR, -1);
  355         }
  356 }
  357 
  358 /*
  359  * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
  360  * Should be called with the same mutex as was passed to cv_wait held.
  361  */
  362 void
  363 cv_broadcastpri(struct cv *cvp, int pri)
  364 {
  365 
  366         if (cvp->cv_waiters > 0) {
  367                 cvp->cv_waiters = 0;
  368                 sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri);
  369         }
  370 }

Cache object: 514ef04a55b0f9439a0cc38e70c076b0


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