root/kern/kern_synch.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tsleep
  2. sleep_setup
  3. sleep_finish
  4. sleep_setup_timeout
  5. sleep_finish_timeout
  6. sleep_setup_signal
  7. sleep_finish_signal
  8. endtsleep
  9. unsleep
  10. wakeup_n
  11. wakeup
  12. sys_sched_yield
  13. sys_thrsleep
  14. sys_thrwakeup

    1 /*      $OpenBSD: kern_synch.c,v 1.80 2007/05/16 17:27:30 art 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 struct slpque {
   71         struct proc *sq_head;
   72         struct proc **sq_tailp;
   73 } slpque[TABLESIZE];
   74 
   75 /*
   76  * During autoconfiguration or after a panic, a sleep will simply
   77  * lower the priority briefly to allow interrupts, then return.
   78  * The priority to be used (safepri) is machine-dependent, thus this
   79  * value is initialized and maintained in the machine-dependent layers.
   80  * This priority will typically be 0, or the lowest priority
   81  * that is safe for use on the interrupt stack; it can be made
   82  * higher to block network software interrupts after panics.
   83  */
   84 int safepri;
   85 
   86 /*
   87  * General sleep call.  Suspends the current process until a wakeup is
   88  * performed on the specified identifier.  The process will then be made
   89  * runnable with the specified priority.  Sleeps at most timo/hz seconds
   90  * (0 means no timeout).  If pri includes PCATCH flag, signals are checked
   91  * before and after sleeping, else signals are not checked.  Returns 0 if
   92  * awakened, EWOULDBLOCK if the timeout expires.  If PCATCH is set and a
   93  * signal needs to be delivered, ERESTART is returned if the current system
   94  * call should be restarted if possible, and EINTR is returned if the system
   95  * call should be interrupted by the signal (return EINTR).
   96  */
   97 int
   98 tsleep(void *ident, int priority, const char *wmesg, int timo)
   99 {
  100         struct sleep_state sls;
  101         int error, error1;
  102 
  103         if (cold || panicstr) {
  104                 int s;
  105                 /*
  106                  * After a panic, or during autoconfiguration,
  107                  * just give interrupts a chance, then just return;
  108                  * don't run any other procs or panic below,
  109                  * in case this is the idle process and already asleep.
  110                  */
  111                 s = splhigh();
  112                 splx(safepri);
  113                 splx(s);
  114                 return (0);
  115         }
  116 
  117         sleep_setup(&sls, ident, priority, wmesg);
  118         sleep_setup_timeout(&sls, timo);
  119         sleep_setup_signal(&sls, priority);
  120 
  121         sleep_finish(&sls, 1);
  122         error1 = sleep_finish_timeout(&sls);
  123         error = sleep_finish_signal(&sls);
  124 
  125         /* Signal errors are higher priority than timeouts. */
  126         if (error == 0 && error1 != 0)
  127                 error = error1;
  128 
  129         return (error);
  130 }
  131 
  132 void
  133 sleep_setup(struct sleep_state *sls, void *ident, int prio, const char *wmesg)
  134 {
  135         struct proc *p = curproc;
  136         struct slpque *qp;
  137 
  138 #ifdef DIAGNOSTIC
  139         if (ident == NULL)
  140                 panic("tsleep: no ident");
  141         if (p->p_stat != SONPROC)
  142                 panic("tsleep: not SONPROC");
  143         if (p->p_back != NULL)
  144                 panic("tsleep: p_back not NULL");
  145 #endif
  146 
  147 #ifdef KTRACE
  148         if (KTRPOINT(p, KTR_CSW))
  149                 ktrcsw(p, 1, 0);
  150 #endif
  151 
  152         sls->sls_catch = 0;
  153         sls->sls_do_sleep = 1;
  154         sls->sls_sig = 1;
  155 
  156         SCHED_LOCK(sls->sls_s);
  157 
  158         p->p_wchan = ident;
  159         p->p_wmesg = wmesg;
  160         p->p_slptime = 0;
  161         p->p_priority = prio & PRIMASK;
  162         qp = &slpque[LOOKUP(ident)];
  163         if (qp->sq_head == 0)
  164                 qp->sq_head = p;
  165         else
  166                 *qp->sq_tailp = p;
  167         *(qp->sq_tailp = &p->p_forw) = NULL;
  168 }
  169 
  170 void
  171 sleep_finish(struct sleep_state *sls, int do_sleep)
  172 {
  173         struct proc *p = curproc;
  174 
  175         if (sls->sls_do_sleep && do_sleep) {
  176                 p->p_stat = SSLEEP;
  177                 p->p_stats->p_ru.ru_nvcsw++;
  178                 SCHED_ASSERT_LOCKED();
  179                 mi_switch();
  180         } else if (!do_sleep) {
  181                 unsleep(p);
  182 #ifdef DIAGNOSTIC
  183                 if (p->p_stat != SONPROC)
  184                         panic("sleep_finish !SONPROC");
  185 #endif
  186         }
  187 
  188         p->p_cpu->ci_schedstate.spc_curpriority = p->p_usrpri;
  189         SCHED_UNLOCK(sls->sls_s);
  190 
  191         /*
  192          * Even though this belongs to the signal handling part of sleep,
  193          * we need to clear it before the ktrace.
  194          */
  195         atomic_clearbits_int(&p->p_flag, P_SINTR);
  196 
  197 #ifdef KTRACE
  198         if (KTRPOINT(p, KTR_CSW))
  199                 ktrcsw(p, 0, 0);
  200 #endif
  201 }
  202 
  203 void
  204 sleep_setup_timeout(struct sleep_state *sls, int timo)
  205 {
  206         if (timo)
  207                 timeout_add(&curproc->p_sleep_to, timo);
  208 }
  209 
  210 int
  211 sleep_finish_timeout(struct sleep_state *sls)
  212 {
  213         struct proc *p = curproc;
  214 
  215         if (p->p_flag & P_TIMEOUT) {
  216                 atomic_clearbits_int(&p->p_flag, P_TIMEOUT);
  217                 return (EWOULDBLOCK);
  218         } else if (timeout_pending(&p->p_sleep_to)) {
  219                 timeout_del(&p->p_sleep_to);
  220         }
  221 
  222         return (0);
  223 }
  224 
  225 void
  226 sleep_setup_signal(struct sleep_state *sls, int prio)
  227 {
  228         struct proc *p = curproc;
  229 
  230         if ((sls->sls_catch = (prio & PCATCH)) == 0)
  231                 return;
  232 
  233         /*
  234          * We put ourselves on the sleep queue and start our timeout
  235          * before calling CURSIG, as we could stop there, and a wakeup
  236          * or a SIGCONT (or both) could occur while we were stopped.
  237          * A SIGCONT would cause us to be marked as SSLEEP
  238          * without resuming us, thus we must be ready for sleep
  239          * when CURSIG is called.  If the wakeup happens while we're
  240          * stopped, p->p_wchan will be 0 upon return from CURSIG.
  241          */
  242         atomic_setbits_int(&p->p_flag, P_SINTR);
  243         if ((sls->sls_sig = CURSIG(p)) != 0) {
  244                 if (p->p_wchan)
  245                         unsleep(p);
  246                 p->p_stat = SONPROC;
  247                 sls->sls_do_sleep = 0;
  248         } else if (p->p_wchan == 0) {
  249                 sls->sls_catch = 0;
  250                 sls->sls_do_sleep = 0;
  251         }
  252 }
  253 
  254 int
  255 sleep_finish_signal(struct sleep_state *sls)
  256 {
  257         struct proc *p = curproc;
  258 
  259         if (sls->sls_catch != 0) {
  260                 if (sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0) {
  261                         if (p->p_sigacts->ps_sigintr & sigmask(sls->sls_sig))
  262                                 return (EINTR);
  263                         return (ERESTART);
  264                 }
  265         }
  266 
  267         return (0);
  268 }
  269 
  270 /*
  271  * Implement timeout for tsleep.
  272  * If process hasn't been awakened (wchan non-zero),
  273  * set timeout flag and undo the sleep.  If proc
  274  * is stopped, just unsleep so it will remain stopped.
  275  */
  276 void
  277 endtsleep(void *arg)
  278 {
  279         struct proc *p = arg;
  280         int s;
  281 
  282         SCHED_LOCK(s);
  283         if (p->p_wchan) {
  284                 if (p->p_stat == SSLEEP)
  285                         setrunnable(p);
  286                 else
  287                         unsleep(p);
  288                 atomic_setbits_int(&p->p_flag, P_TIMEOUT);
  289         }
  290         SCHED_UNLOCK(s);
  291 }
  292 
  293 /*
  294  * Remove a process from its wait queue
  295  */
  296 void
  297 unsleep(struct proc *p)
  298 {
  299         struct slpque *qp;
  300         struct proc **hp;
  301 
  302         if (p->p_wchan) {
  303                 hp = &(qp = &slpque[LOOKUP(p->p_wchan)])->sq_head;
  304                 while (*hp != p)
  305                         hp = &(*hp)->p_forw;
  306                 *hp = p->p_forw;
  307                 if (qp->sq_tailp == &p->p_forw)
  308                         qp->sq_tailp = hp;
  309                 p->p_wchan = 0;
  310         }
  311 }
  312 
  313 /*
  314  * Make a number of processes sleeping on the specified identifier runnable.
  315  */
  316 void
  317 wakeup_n(void *ident, int n)
  318 {
  319         struct slpque *qp;
  320         struct proc *p, **q;
  321         int s;
  322 
  323         SCHED_LOCK(s);
  324         qp = &slpque[LOOKUP(ident)];
  325 restart:
  326         for (q = &qp->sq_head; (p = *q) != NULL; ) {
  327 #ifdef DIAGNOSTIC
  328                 if (p->p_back)
  329                         panic("wakeup: p_back not NULL");
  330                 if (p->p_stat != SSLEEP && p->p_stat != SSTOP)
  331                         panic("wakeup: p_stat is %d", (int)p->p_stat);
  332 #endif
  333                 if (p->p_wchan == ident) {
  334                         --n;
  335                         p->p_wchan = 0;
  336                         *q = p->p_forw;
  337                         if (qp->sq_tailp == &p->p_forw)
  338                                 qp->sq_tailp = q;
  339                         if (p->p_stat == SSLEEP) {
  340                                 /* OPTIMIZED EXPANSION OF setrunnable(p); */
  341                                 if (p->p_slptime > 1)
  342                                         updatepri(p);
  343                                 p->p_slptime = 0;
  344                                 p->p_stat = SRUN;
  345 
  346                                 /*
  347                                  * Since curpriority is a user priority,
  348                                  * p->p_priority is always better than
  349                                  * curpriority on the last CPU on
  350                                  * which it ran.
  351                                  *
  352                                  * XXXSMP See affinity comment in
  353                                  * resched_proc().
  354                                  */
  355                                 setrunqueue(p);
  356                                 KASSERT(p->p_cpu != NULL);
  357                                 need_resched(p->p_cpu);
  358                                 /* END INLINE EXPANSION */
  359 
  360                                 if (n != 0)
  361                                         goto restart;
  362                                 else
  363                                         break;
  364                         }
  365                 } else
  366                         q = &p->p_forw;
  367         }
  368         SCHED_UNLOCK(s);
  369 }
  370 
  371 /*
  372  * Make all processes sleeping on the specified identifier runnable.
  373  */
  374 void
  375 wakeup(void *chan)
  376 {
  377         wakeup_n(chan, -1);
  378 }
  379 
  380 int
  381 sys_sched_yield(struct proc *p, void *v, register_t *retval)
  382 {
  383         yield();
  384         return (0);
  385 }
  386 
  387 #ifdef RTHREADS
  388 
  389 int
  390 sys_thrsleep(struct proc *p, void *v, register_t *revtal)
  391 {
  392         struct sys_thrsleep_args *uap = v;
  393         long ident = (long)SCARG(uap, ident);
  394         int timo = SCARG(uap, timeout);
  395         _spinlock_lock_t *lock = SCARG(uap, lock);
  396         _spinlock_lock_t unlocked = _SPINLOCK_UNLOCKED;
  397         int error;
  398 
  399         p->p_thrslpid = ident;
  400 
  401         if (lock)
  402                 copyout(&unlocked, lock, sizeof(unlocked));
  403         if (hz > 1000)
  404                 timo = timo * (hz / 1000);
  405         else
  406                 timo = timo / (1000 / hz);
  407         if (timo < 0)
  408                 timo = 0;
  409         error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep", timo);
  410 
  411         if (error == ERESTART)
  412                 error = EINTR;
  413 
  414         return (error);
  415 
  416 }
  417 
  418 int
  419 sys_thrwakeup(struct proc *p, void *v, register_t *retval)
  420 {
  421         struct sys_thrwakeup_args *uap = v;
  422         long ident = (long)SCARG(uap, ident);
  423         int n = SCARG(uap, n);
  424         struct proc *q;
  425         int found = 0;
  426         
  427         TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) {
  428                 if (q->p_thrslpid == ident) {
  429                         wakeup(&q->p_thrslpid);
  430                         q->p_thrslpid = 0;
  431                         if (++found == n)
  432                                 return (0);
  433                 }
  434         }
  435         if (!found)
  436                 return (ESRCH);
  437 
  438         return (0);
  439 }
  440 #endif

/* [<][>][^][v][top][bottom][index][help] */