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

Cache object: 1ca8581f169b18ffef5851c021f67545


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