LCOV - code coverage report
Current view: top level - kern - kern_synch.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 314 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: kern_synch.c,v 1.146 2018/05/31 02:16:22 guenther 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/signalvar.h>
      45             : #include <sys/resourcevar.h>
      46             : #include <sys/sched.h>
      47             : #include <sys/timeout.h>
      48             : #include <sys/mount.h>
      49             : #include <sys/syscallargs.h>
      50             : #include <sys/pool.h>
      51             : #include <sys/refcnt.h>
      52             : #include <sys/atomic.h>
      53             : #include <sys/witness.h>
      54             : #include <ddb/db_output.h>
      55             : 
      56             : #include <machine/spinlock.h>
      57             : 
      58             : #ifdef KTRACE
      59             : #include <sys/ktrace.h>
      60             : #endif
      61             : 
      62             : int     thrsleep(struct proc *, struct sys___thrsleep_args *);
      63             : int     thrsleep_unlock(void *);
      64             : 
      65             : /*
      66             :  * We're only looking at 7 bits of the address; everything is
      67             :  * aligned to 4, lots of things are aligned to greater powers
      68             :  * of 2.  Shift right by 8, i.e. drop the bottom 256 worth.
      69             :  */
      70             : #define TABLESIZE       128
      71             : #define LOOKUP(x)       (((long)(x) >> 8) & (TABLESIZE - 1))
      72             : TAILQ_HEAD(slpque,proc) slpque[TABLESIZE];
      73             : 
      74             : void
      75           0 : sleep_queue_init(void)
      76             : {
      77             :         int i;
      78             : 
      79           0 :         for (i = 0; i < TABLESIZE; i++)
      80           0 :                 TAILQ_INIT(&slpque[i]);
      81           0 : }
      82             : 
      83             : 
      84             : /*
      85             :  * During autoconfiguration or after a panic, a sleep will simply
      86             :  * lower the priority briefly to allow interrupts, then return.
      87             :  * The priority to be used (safepri) is machine-dependent, thus this
      88             :  * value is initialized and maintained in the machine-dependent layers.
      89             :  * This priority will typically be 0, or the lowest priority
      90             :  * that is safe for use on the interrupt stack; it can be made
      91             :  * higher to block network software interrupts after panics.
      92             :  */
      93             : extern int safepri;
      94             : 
      95             : /*
      96             :  * General sleep call.  Suspends the current process until a wakeup is
      97             :  * performed on the specified identifier.  The process will then be made
      98             :  * runnable with the specified priority.  Sleeps at most timo/hz seconds
      99             :  * (0 means no timeout).  If pri includes PCATCH flag, signals are checked
     100             :  * before and after sleeping, else signals are not checked.  Returns 0 if
     101             :  * awakened, EWOULDBLOCK if the timeout expires.  If PCATCH is set and a
     102             :  * signal needs to be delivered, ERESTART is returned if the current system
     103             :  * call should be restarted if possible, and EINTR is returned if the system
     104             :  * call should be interrupted by the signal (return EINTR).
     105             :  */
     106             : int
     107           0 : tsleep(const volatile void *ident, int priority, const char *wmesg, int timo)
     108             : {
     109           0 :         struct sleep_state sls;
     110             : #ifdef MULTIPROCESSOR
     111             :         int hold_count;
     112             : #endif
     113             : 
     114           0 :         KASSERT((priority & ~(PRIMASK | PCATCH)) == 0);
     115             : 
     116             : #ifdef MULTIPROCESSOR
     117           0 :         KASSERT(timo || _kernel_lock_held());
     118             : #endif
     119             : 
     120             : #ifdef DDB
     121           0 :         if (cold == 2)
     122           0 :                 db_stack_dump();
     123             : #endif
     124           0 :         if (cold || panicstr) {
     125             :                 int s;
     126             :                 /*
     127             :                  * After a panic, or during autoconfiguration,
     128             :                  * just give interrupts a chance, then just return;
     129             :                  * don't run any other procs or panic below,
     130             :                  * in case this is the idle process and already asleep.
     131             :                  */
     132           0 :                 s = splhigh();
     133           0 :                 splx(safepri);
     134             : #ifdef MULTIPROCESSOR
     135           0 :                 if (_kernel_lock_held()) {
     136           0 :                         hold_count = __mp_release_all(&kernel_lock);
     137           0 :                         __mp_acquire_count(&kernel_lock, hold_count);
     138           0 :                 }
     139             : #endif
     140           0 :                 splx(s);
     141             :                 return (0);
     142             :         }
     143             : 
     144           0 :         sleep_setup(&sls, ident, priority, wmesg);
     145           0 :         sleep_setup_timeout(&sls, timo);
     146           0 :         sleep_setup_signal(&sls, priority);
     147             : 
     148           0 :         return sleep_finish_all(&sls, 1);
     149           0 : }
     150             : 
     151             : int
     152           0 : sleep_finish_all(struct sleep_state *sls, int do_sleep)
     153             : {
     154             :         int error, error1;
     155             : 
     156           0 :         sleep_finish(sls, do_sleep);
     157           0 :         error1 = sleep_finish_timeout(sls);
     158           0 :         error = sleep_finish_signal(sls);
     159             : 
     160             :         /* Signal errors are higher priority than timeouts. */
     161           0 :         if (error == 0 && error1 != 0)
     162           0 :                 error = error1;
     163             : 
     164           0 :         return error;
     165             : }
     166             : 
     167             : /*
     168             :  * Same as tsleep, but if we have a mutex provided, then once we've
     169             :  * entered the sleep queue we drop the mutex. After sleeping we re-lock.
     170             :  */
     171             : int
     172           0 : msleep(const volatile void *ident, struct mutex *mtx, int priority,
     173             :     const char *wmesg, int timo)
     174             : {
     175           0 :         struct sleep_state sls;
     176             :         int error, spl;
     177             : #ifdef MULTIPROCESSOR
     178             :         int hold_count;
     179             : #endif
     180             :         WITNESS_SAVE_DECL(lock_fl);
     181             : 
     182           0 :         KASSERT((priority & ~(PRIMASK | PCATCH | PNORELOCK)) == 0);
     183           0 :         KASSERT(mtx != NULL);
     184             : 
     185           0 :         if (cold || panicstr) {
     186             :                 /*
     187             :                  * After a panic, or during autoconfiguration,
     188             :                  * just give interrupts a chance, then just return;
     189             :                  * don't run any other procs or panic below,
     190             :                  * in case this is the idle process and already asleep.
     191             :                  */
     192           0 :                 spl = MUTEX_OLDIPL(mtx);
     193           0 :                 MUTEX_OLDIPL(mtx) = safepri;
     194           0 :                 mtx_leave(mtx);
     195             : #ifdef MULTIPROCESSOR
     196           0 :                 if (_kernel_lock_held()) {
     197           0 :                         hold_count = __mp_release_all(&kernel_lock);
     198           0 :                         __mp_acquire_count(&kernel_lock, hold_count);
     199           0 :                 }
     200             : #endif
     201           0 :                 if ((priority & PNORELOCK) == 0) {
     202           0 :                         mtx_enter(mtx);
     203           0 :                         MUTEX_OLDIPL(mtx) = spl;
     204           0 :                 } else
     205           0 :                         splx(spl);
     206           0 :                 return (0);
     207             :         }
     208             : 
     209           0 :         sleep_setup(&sls, ident, priority, wmesg);
     210           0 :         sleep_setup_timeout(&sls, timo);
     211           0 :         sleep_setup_signal(&sls, priority);
     212             : 
     213             :         WITNESS_SAVE(MUTEX_LOCK_OBJECT(mtx), lock_fl);
     214             : 
     215             :         /* XXX - We need to make sure that the mutex doesn't
     216             :          * unblock splsched. This can be made a bit more
     217             :          * correct when the sched_lock is a mutex.
     218             :          */
     219           0 :         spl = MUTEX_OLDIPL(mtx);
     220           0 :         MUTEX_OLDIPL(mtx) = splsched();
     221           0 :         mtx_leave(mtx);
     222             : 
     223           0 :         error = sleep_finish_all(&sls, 1);
     224             : 
     225           0 :         if ((priority & PNORELOCK) == 0) {
     226           0 :                 mtx_enter(mtx);
     227           0 :                 MUTEX_OLDIPL(mtx) = spl; /* put the ipl back */
     228             :                 WITNESS_RESTORE(MUTEX_LOCK_OBJECT(mtx), lock_fl);
     229           0 :         } else
     230           0 :                 splx(spl);
     231             : 
     232           0 :         return error;
     233           0 : }
     234             : 
     235             : /*
     236             :  * Same as tsleep, but if we have a rwlock provided, then once we've
     237             :  * entered the sleep queue we drop the it. After sleeping we re-lock.
     238             :  */
     239             : int
     240           0 : rwsleep(const volatile void *ident, struct rwlock *rwl, int priority,
     241             :     const char *wmesg, int timo)
     242             : {
     243           0 :         struct sleep_state sls;
     244             :         int error, status;
     245             :         WITNESS_SAVE_DECL(lock_fl);
     246             : 
     247           0 :         KASSERT((priority & ~(PRIMASK | PCATCH | PNORELOCK)) == 0);
     248           0 :         rw_assert_anylock(rwl);
     249           0 :         status = rw_status(rwl);
     250             : 
     251           0 :         sleep_setup(&sls, ident, priority, wmesg);
     252           0 :         sleep_setup_timeout(&sls, timo);
     253           0 :         sleep_setup_signal(&sls, priority);
     254             : 
     255             :         WITNESS_SAVE(&rwl->rwl_lock_obj, lock_fl);
     256             : 
     257           0 :         rw_exit(rwl);
     258             : 
     259           0 :         error = sleep_finish_all(&sls, 1);
     260             : 
     261           0 :         if ((priority & PNORELOCK) == 0) {
     262           0 :                 rw_enter(rwl, status);
     263             :                 WITNESS_RESTORE(&rwl->rwl_lock_obj, lock_fl);
     264           0 :         }
     265             : 
     266           0 :         return error;
     267           0 : }
     268             : 
     269             : void
     270           0 : sleep_setup(struct sleep_state *sls, const volatile void *ident, int prio,
     271             :     const char *wmesg)
     272             : {
     273           0 :         struct proc *p = curproc;
     274             : 
     275             : #ifdef DIAGNOSTIC
     276           0 :         if (p->p_flag & P_CANTSLEEP)
     277           0 :                 panic("sleep: %s failed insomnia", p->p_p->ps_comm);
     278           0 :         if (ident == NULL)
     279           0 :                 panic("tsleep: no ident");
     280           0 :         if (p->p_stat != SONPROC)
     281           0 :                 panic("tsleep: not SONPROC");
     282             : #endif
     283             : 
     284           0 :         sls->sls_catch = 0;
     285           0 :         sls->sls_do_sleep = 1;
     286           0 :         sls->sls_sig = 1;
     287             : 
     288           0 :         SCHED_LOCK(sls->sls_s);
     289             : 
     290           0 :         p->p_wchan = ident;
     291           0 :         p->p_wmesg = wmesg;
     292           0 :         p->p_slptime = 0;
     293           0 :         p->p_priority = prio & PRIMASK;
     294           0 :         TAILQ_INSERT_TAIL(&slpque[LOOKUP(ident)], p, p_runq);
     295           0 : }
     296             : 
     297             : void
     298           0 : sleep_finish(struct sleep_state *sls, int do_sleep)
     299             : {
     300           0 :         struct proc *p = curproc;
     301             : 
     302           0 :         if (sls->sls_do_sleep && do_sleep) {
     303           0 :                 p->p_stat = SSLEEP;
     304           0 :                 p->p_ru.ru_nvcsw++;
     305           0 :                 SCHED_ASSERT_LOCKED();
     306           0 :                 mi_switch();
     307           0 :         } else if (!do_sleep) {
     308           0 :                 unsleep(p);
     309           0 :         }
     310             : 
     311             : #ifdef DIAGNOSTIC
     312           0 :         if (p->p_stat != SONPROC)
     313           0 :                 panic("sleep_finish !SONPROC");
     314             : #endif
     315             : 
     316           0 :         p->p_cpu->ci_schedstate.spc_curpriority = p->p_usrpri;
     317           0 :         SCHED_UNLOCK(sls->sls_s);
     318             : 
     319             :         /*
     320             :          * Even though this belongs to the signal handling part of sleep,
     321             :          * we need to clear it before the ktrace.
     322             :          */
     323           0 :         atomic_clearbits_int(&p->p_flag, P_SINTR);
     324           0 : }
     325             : 
     326             : void
     327           0 : sleep_setup_timeout(struct sleep_state *sls, int timo)
     328             : {
     329           0 :         if (timo)
     330           0 :                 timeout_add(&curproc->p_sleep_to, timo);
     331           0 : }
     332             : 
     333             : int
     334           0 : sleep_finish_timeout(struct sleep_state *sls)
     335             : {
     336           0 :         struct proc *p = curproc;
     337             : 
     338           0 :         if (p->p_flag & P_TIMEOUT) {
     339           0 :                 atomic_clearbits_int(&p->p_flag, P_TIMEOUT);
     340           0 :                 return (EWOULDBLOCK);
     341             :         } else
     342           0 :                 timeout_del(&p->p_sleep_to);
     343             : 
     344           0 :         return (0);
     345           0 : }
     346             : 
     347             : void
     348           0 : sleep_setup_signal(struct sleep_state *sls, int prio)
     349             : {
     350           0 :         struct proc *p = curproc;
     351             : 
     352           0 :         if ((sls->sls_catch = (prio & PCATCH)) == 0)
     353           0 :                 return;
     354             : 
     355             :         /*
     356             :          * We put ourselves on the sleep queue and start our timeout
     357             :          * before calling CURSIG, as we could stop there, and a wakeup
     358             :          * or a SIGCONT (or both) could occur while we were stopped.
     359             :          * A SIGCONT would cause us to be marked as SSLEEP
     360             :          * without resuming us, thus we must be ready for sleep
     361             :          * when CURSIG is called.  If the wakeup happens while we're
     362             :          * stopped, p->p_wchan will be 0 upon return from CURSIG.
     363             :          */
     364           0 :         atomic_setbits_int(&p->p_flag, P_SINTR);
     365           0 :         if (p->p_p->ps_single != NULL || (sls->sls_sig = CURSIG(p)) != 0) {
     366           0 :                 if (p->p_wchan)
     367           0 :                         unsleep(p);
     368           0 :                 p->p_stat = SONPROC;
     369           0 :                 sls->sls_do_sleep = 0;
     370           0 :         } else if (p->p_wchan == 0) {
     371           0 :                 sls->sls_catch = 0;
     372           0 :                 sls->sls_do_sleep = 0;
     373           0 :         }
     374           0 : }
     375             : 
     376             : int
     377           0 : sleep_finish_signal(struct sleep_state *sls)
     378             : {
     379           0 :         struct proc *p = curproc;
     380             :         int error;
     381             : 
     382           0 :         if (sls->sls_catch != 0) {
     383           0 :                 if ((error = single_thread_check(p, 1)))
     384           0 :                         return (error);
     385           0 :                 if (sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0) {
     386           0 :                         if (p->p_p->ps_sigacts->ps_sigintr &
     387           0 :                             sigmask(sls->sls_sig))
     388           0 :                                 return (EINTR);
     389           0 :                         return (ERESTART);
     390             :                 }
     391             :         }
     392             : 
     393           0 :         return (0);
     394           0 : }
     395             : 
     396             : /*
     397             :  * Implement timeout for tsleep.
     398             :  * If process hasn't been awakened (wchan non-zero),
     399             :  * set timeout flag and undo the sleep.  If proc
     400             :  * is stopped, just unsleep so it will remain stopped.
     401             :  */
     402             : void
     403           0 : endtsleep(void *arg)
     404             : {
     405           0 :         struct proc *p = arg;
     406             :         int s;
     407             : 
     408           0 :         SCHED_LOCK(s);
     409           0 :         if (p->p_wchan) {
     410           0 :                 if (p->p_stat == SSLEEP)
     411           0 :                         setrunnable(p);
     412             :                 else
     413           0 :                         unsleep(p);
     414           0 :                 atomic_setbits_int(&p->p_flag, P_TIMEOUT);
     415           0 :         }
     416           0 :         SCHED_UNLOCK(s);
     417           0 : }
     418             : 
     419             : /*
     420             :  * Remove a process from its wait queue
     421             :  */
     422             : void
     423           0 : unsleep(struct proc *p)
     424             : {
     425           0 :         SCHED_ASSERT_LOCKED();
     426             : 
     427           0 :         if (p->p_wchan) {
     428           0 :                 TAILQ_REMOVE(&slpque[LOOKUP(p->p_wchan)], p, p_runq);
     429           0 :                 p->p_wchan = NULL;
     430           0 :         }
     431           0 : }
     432             : 
     433             : /*
     434             :  * Make a number of processes sleeping on the specified identifier runnable.
     435             :  */
     436             : void
     437           0 : wakeup_n(const volatile void *ident, int n)
     438             : {
     439             :         struct slpque *qp;
     440             :         struct proc *p;
     441             :         struct proc *pnext;
     442             :         int s;
     443             : 
     444           0 :         SCHED_LOCK(s);
     445           0 :         qp = &slpque[LOOKUP(ident)];
     446           0 :         for (p = TAILQ_FIRST(qp); p != NULL && n != 0; p = pnext) {
     447           0 :                 pnext = TAILQ_NEXT(p, p_runq);
     448             : #ifdef DIAGNOSTIC
     449             :                 /*
     450             :                  * If the rwlock passed to rwsleep() is contended, the
     451             :                  * CPU will end up calling wakeup() between sleep_setup()
     452             :                  * and sleep_finish().
     453             :                  */
     454           0 :                 if (p == curproc) {
     455           0 :                         KASSERT(p->p_stat == SONPROC);
     456             :                         continue;
     457             :                 }
     458           0 :                 if (p->p_stat != SSLEEP && p->p_stat != SSTOP)
     459           0 :                         panic("wakeup: p_stat is %d", (int)p->p_stat);
     460             : #endif
     461           0 :                 if (p->p_wchan == ident) {
     462           0 :                         --n;
     463           0 :                         p->p_wchan = 0;
     464           0 :                         TAILQ_REMOVE(qp, p, p_runq);
     465           0 :                         if (p->p_stat == SSLEEP)
     466           0 :                                 setrunnable(p);
     467             :                 }
     468             :         }
     469           0 :         SCHED_UNLOCK(s);
     470           0 : }
     471             : 
     472             : /*
     473             :  * Make all processes sleeping on the specified identifier runnable.
     474             :  */
     475             : void
     476           0 : wakeup(const volatile void *chan)
     477             : {
     478           0 :         wakeup_n(chan, -1);
     479           0 : }
     480             : 
     481             : int
     482           0 : sys_sched_yield(struct proc *p, void *v, register_t *retval)
     483             : {
     484             :         struct proc *q;
     485             :         int s;
     486             : 
     487           0 :         SCHED_LOCK(s);
     488             :         /*
     489             :          * If one of the threads of a multi-threaded process called
     490             :          * sched_yield(2), drop its priority to ensure its siblings
     491             :          * can make some progress.
     492             :          */
     493           0 :         p->p_priority = p->p_usrpri;
     494           0 :         TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link)
     495           0 :                 p->p_priority = max(p->p_priority, q->p_priority);
     496           0 :         p->p_stat = SRUN;
     497           0 :         setrunqueue(p);
     498           0 :         p->p_ru.ru_nvcsw++;
     499           0 :         mi_switch();
     500           0 :         SCHED_UNLOCK(s);
     501             : 
     502           0 :         return (0);
     503             : }
     504             : 
     505             : int
     506           0 : thrsleep_unlock(void *lock)
     507             : {
     508             :         static _atomic_lock_t unlocked = _ATOMIC_LOCK_UNLOCKED;
     509           0 :         _atomic_lock_t *atomiclock = lock;
     510             : 
     511           0 :         if (!lock)
     512           0 :                 return 0;
     513             : 
     514           0 :         return copyout(&unlocked, atomiclock, sizeof(unlocked));
     515           0 : }
     516             : 
     517             : static int globalsleepaddr;
     518             : 
     519             : int
     520           0 : thrsleep(struct proc *p, struct sys___thrsleep_args *v)
     521             : {
     522             :         struct sys___thrsleep_args /* {
     523             :                 syscallarg(const volatile void *) ident;
     524             :                 syscallarg(clockid_t) clock_id;
     525             :                 syscallarg(const struct timespec *) tp;
     526             :                 syscallarg(void *) lock;
     527             :                 syscallarg(const int *) abort;
     528             :         } */ *uap = v;
     529           0 :         long ident = (long)SCARG(uap, ident);
     530           0 :         struct timespec *tsp = (struct timespec *)SCARG(uap, tp);
     531           0 :         void *lock = SCARG(uap, lock);
     532             :         uint64_t to_ticks = 0;
     533           0 :         int abort, error;
     534           0 :         clockid_t clock_id = SCARG(uap, clock_id);
     535             : 
     536           0 :         if (ident == 0)
     537           0 :                 return (EINVAL);
     538           0 :         if (tsp != NULL) {
     539           0 :                 struct timespec now;
     540             : 
     541           0 :                 if ((error = clock_gettime(p, clock_id, &now)))
     542           0 :                         return (error);
     543             : #ifdef KTRACE
     544           0 :                 if (KTRPOINT(p, KTR_STRUCT))
     545           0 :                         ktrabstimespec(p, tsp);
     546             : #endif
     547             : 
     548           0 :                 if (timespeccmp(tsp, &now, <)) {
     549             :                         /* already passed: still do the unlock */
     550           0 :                         if ((error = thrsleep_unlock(lock)))
     551           0 :                                 return (error);
     552           0 :                         return (EWOULDBLOCK);
     553             :                 }
     554             : 
     555           0 :                 timespecsub(tsp, &now, tsp);
     556           0 :                 to_ticks = (uint64_t)hz * tsp->tv_sec +
     557           0 :                     (tsp->tv_nsec + tick * 1000 - 1) / (tick * 1000) + 1;
     558           0 :                 if (to_ticks > INT_MAX)
     559             :                         to_ticks = INT_MAX;
     560           0 :         }
     561             : 
     562           0 :         p->p_thrslpid = ident;
     563             : 
     564           0 :         if ((error = thrsleep_unlock(lock)))
     565             :                 goto out;
     566             : 
     567           0 :         if (SCARG(uap, abort) != NULL) {
     568           0 :                 if ((error = copyin(SCARG(uap, abort), &abort,
     569           0 :                     sizeof(abort))) != 0)
     570             :                         goto out;
     571           0 :                 if (abort) {
     572             :                         error = EINTR;
     573           0 :                         goto out;
     574             :                 }
     575             :         }
     576             : 
     577           0 :         if (p->p_thrslpid == 0)
     578           0 :                 error = 0;
     579             :         else {
     580           0 :                 void *sleepaddr = &p->p_thrslpid;
     581           0 :                 if (ident == -1)
     582             :                         sleepaddr = &globalsleepaddr;
     583           0 :                 error = tsleep(sleepaddr, PUSER | PCATCH, "thrsleep",
     584           0 :                     (int)to_ticks);
     585             :         }
     586             : 
     587             : out:
     588           0 :         p->p_thrslpid = 0;
     589             : 
     590           0 :         if (error == ERESTART)
     591           0 :                 error = ECANCELED;
     592             : 
     593           0 :         return (error);
     594             : 
     595           0 : }
     596             : 
     597             : int
     598           0 : sys___thrsleep(struct proc *p, void *v, register_t *retval)
     599             : {
     600             :         struct sys___thrsleep_args /* {
     601             :                 syscallarg(const volatile void *) ident;
     602             :                 syscallarg(clockid_t) clock_id;
     603             :                 syscallarg(struct timespec *) tp;
     604             :                 syscallarg(void *) lock;
     605             :                 syscallarg(const int *) abort;
     606           0 :         } */ *uap = v;
     607           0 :         struct timespec ts;
     608             :         int error;
     609             : 
     610           0 :         if (SCARG(uap, tp) != NULL) {
     611           0 :                 if ((error = copyin(SCARG(uap, tp), &ts, sizeof(ts)))) {
     612           0 :                         *retval = error;
     613           0 :                         return 0;
     614             :                 }
     615           0 :                 if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000) {
     616           0 :                         *retval = EINVAL;
     617           0 :                         return 0;
     618             :                 }
     619           0 :                 SCARG(uap, tp) = &ts;
     620           0 :         }
     621             : 
     622           0 :         *retval = thrsleep(p, uap);
     623           0 :         return 0;
     624           0 : }
     625             : 
     626             : int
     627           0 : sys___thrwakeup(struct proc *p, void *v, register_t *retval)
     628             : {
     629             :         struct sys___thrwakeup_args /* {
     630             :                 syscallarg(const volatile void *) ident;
     631             :                 syscallarg(int) n;
     632           0 :         } */ *uap = v;
     633           0 :         long ident = (long)SCARG(uap, ident);
     634           0 :         int n = SCARG(uap, n);
     635             :         struct proc *q;
     636             :         int found = 0;
     637             : 
     638           0 :         if (ident == 0)
     639           0 :                 *retval = EINVAL;
     640           0 :         else if (ident == -1)
     641           0 :                 wakeup(&globalsleepaddr);
     642             :         else {
     643           0 :                 TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) {
     644           0 :                         if (q->p_thrslpid == ident) {
     645           0 :                                 wakeup_one(&q->p_thrslpid);
     646           0 :                                 q->p_thrslpid = 0;
     647           0 :                                 if (++found == n)
     648             :                                         break;
     649             :                         }
     650             :                 }
     651           0 :                 *retval = found ? 0 : ESRCH;
     652             :         }
     653             : 
     654           0 :         return (0);
     655             : }
     656             : 
     657             : void
     658           0 : refcnt_init(struct refcnt *r)
     659             : {
     660           0 :         r->refs = 1;
     661           0 : }
     662             : 
     663             : void
     664           0 : refcnt_take(struct refcnt *r)
     665             : {
     666             : #ifdef DIAGNOSTIC
     667             :         u_int refcnt;
     668             : 
     669           0 :         refcnt = atomic_inc_int_nv(&r->refs);
     670           0 :         KASSERT(refcnt != 0);
     671             : #else
     672             :         atomic_inc_int(&r->refs);
     673             : #endif
     674           0 : }
     675             : 
     676             : int
     677           0 : refcnt_rele(struct refcnt *r)
     678             : {
     679             :         u_int refcnt;
     680             : 
     681           0 :         refcnt = atomic_dec_int_nv(&r->refs);
     682           0 :         KASSERT(refcnt != ~0);
     683             : 
     684           0 :         return (refcnt == 0);
     685             : }
     686             : 
     687             : void
     688           0 : refcnt_rele_wake(struct refcnt *r)
     689             : {
     690           0 :         if (refcnt_rele(r))
     691           0 :                 wakeup_one(r);
     692           0 : }
     693             : 
     694             : void
     695           0 : refcnt_finalize(struct refcnt *r, const char *wmesg)
     696             : {
     697           0 :         struct sleep_state sls;
     698             :         u_int refcnt;
     699             : 
     700           0 :         refcnt = atomic_dec_int_nv(&r->refs);
     701           0 :         while (refcnt) {
     702           0 :                 sleep_setup(&sls, r, PWAIT, wmesg);
     703           0 :                 refcnt = r->refs;
     704           0 :                 sleep_finish(&sls, refcnt);
     705             :         }
     706           0 : }
     707             : 
     708             : void
     709           0 : cond_init(struct cond *c)
     710             : {
     711           0 :         c->c_wait = 1;
     712           0 : }
     713             : 
     714             : void
     715           0 : cond_signal(struct cond *c)
     716             : {
     717           0 :         c->c_wait = 0;
     718             : 
     719           0 :         wakeup_one(c);
     720           0 : }
     721             : 
     722             : void
     723           0 : cond_wait(struct cond *c, const char *wmesg)
     724             : {
     725           0 :         struct sleep_state sls;
     726             :         int wait;
     727             : 
     728           0 :         wait = c->c_wait;
     729           0 :         while (wait) {
     730           0 :                 sleep_setup(&sls, c, PWAIT, wmesg);
     731           0 :                 wait = c->c_wait;
     732           0 :                 sleep_finish(&sls, wait);
     733             :         }
     734           0 : }

Generated by: LCOV version 1.13