FreeBSD/sys/kern/kern_synch.c
/*
 * General sleep call.  Suspends the current thread until a wakeup is
 * performed on the specified identifier.  The thread will then be made
 * runnable with the specified priority.  Sleeps at most sbt units of time
 * (0 means no timeout).  If pri includes the PCATCH flag, let signals
 * interrupt the sleep, otherwise ignore them while sleeping.  Returns 0 if
 * awakened, EWOULDBLOCK if the timeout expires.  If PCATCH is set and a
 * signal becomes pending, ERESTART is returned if the current system
 * call should be restarted if possible, and EINTR is returned if the system
 * call should be interrupted by the signal (return EINTR).
 *
 * The lock argument is unlocked before the caller is suspended, and
 * re-locked before _sleep() returns.  If priority includes the PDROP
 * flag the lock is not re-locked before returning.
 */
General sleep call.  Suspends the current thread until a wakeup is
performed on the specified identifier.  The thread will then be made
runnable with the specified priority.  Sleeps at most sbt units of time
(0 means no timeout).  If pri includes the PCATCH flag, let signals
interrupt the sleep, otherwise ignore them while sleeping.  Returns 0 if
awakened, EWOULDBLOCK if the timeout expires.  If PCATCH is set and a
signal becomes pending, ERESTART is returned if the current system
call should be restarted if possible, and EINTR is returned if the system
call should be interrupted by the signal (return EINTR).

The lock argument is unlocked before the caller is suspended, and
re-locked before _sleep() returns.  If priority includes the PDROP
flag the lock is not re-locked before returning.
General sleep call . Suspends the current thread until a wakeup is performed on the specified identifier . The thread will then be made runnable with the specified priority . Sleeps at most sbt units of time ( 0 means no timeout ) . If pri includes the PCATCH flag let signals interrupt the sleep otherwise ignore them while sleeping . Returns 0 if awakened EWOULDBLOCK if the timeout expires . If PCATCH is set and a signal becomes pending ERESTART is returned if the current system call should be restarted if possible and EINTR is returned if the system call should be interrupted by the signal ( return EINTR ) . The lock argument is unlocked before the caller is suspended and re - locked before _sleep () returns . If priority includes the PDROP flag the lock is not re - locked before returning .
int
_sleep(void *ident, struct lock_object *lock, int priority,
    const char *wmesg, sbintime_t sbt, sbintime_t pr, int flags)
{
	struct thread *td;
	struct proc *p;
	struct lock_class *class;
	uintptr_t lock_state;
	int catch, pri, rval, sleepq_flags;
	WITNESS_SAVE_DECL(lock_witness);
	td = curthread;
	p = td->td_proc;
#ifdef KTRACE
	if (KTRPOINT(td, KTR_CSW))
		ktrcsw(1, 0, wmesg);
#endif
	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
	    "Sleeping on \"%s\"", wmesg);
	KASSERT(sbt != 0 || mtx_owned(&Giant) || lock != NULL,
	    ("sleeping without a lock"));
	KASSERT(p != NULL, ("msleep1"));
	KASSERT(ident != NULL && TD_IS_RUNNING(td), ("msleep"));
	if (priority & PDROP)
		KASSERT(lock != NULL && lock != &Giant.lock_object,
		    ("PDROP requires a non-Giant lock"));
	if (lock != NULL)
		class = LOCK_CLASS(lock);
	else
		class = NULL;
	if (SCHEDULER_STOPPED()) {
		if (lock != NULL && priority & PDROP)
			class->lc_unlock(lock);
		return (0);
	}
	catch = priority & PCATCH;
	pri = priority & PRIMASK;
	if (TD_ON_SLEEPQ(td))
		sleepq_remove(td, td->td_wchan);
	if ((uint8_t *)ident >= &pause_wchan[0] &&
	    (uint8_t *)ident <= &pause_wchan[MAXCPU - 1])
		sleepq_flags = SLEEPQ_PAUSE;
	else
		sleepq_flags = SLEEPQ_SLEEP;
	if (catch)
		sleepq_flags |= SLEEPQ_INTERRUPTIBLE;
	sleepq_lock(ident);
	CTR5(KTR_PROC, "sleep: thread %ld (pid %ld, %s) on %s (%p)",
	    td->td_tid, p->p_pid, td->td_name, wmesg, ident);
	if (lock == &Giant.lock_object)
		mtx_assert(&Giant, MA_OWNED);
	DROP_GIANT();
	if (lock != NULL && lock != &Giant.lock_object &&
	    !(class->lc_flags & LC_SLEEPABLE)) {
		WITNESS_SAVE(lock, lock_witness);
		lock_state = class->lc_unlock(lock);
	} else
		lock_state = -1;
	sleepq_add(ident, lock, wmesg, sleepq_flags, 0);
	if (sbt != 0)
		sleepq_set_timeout_sbt(ident, sbt, pr, flags);
	if (lock != NULL && class->lc_flags & LC_SLEEPABLE) {
		sleepq_release(ident);
		WITNESS_SAVE(lock, lock_witness);
		lock_state = class->lc_unlock(lock);
		sleepq_lock(ident);
	}
	if (sbt != 0 && catch)
		rval = sleepq_timedwait_sig(ident, pri);
	else if (sbt != 0)
		rval = sleepq_timedwait(ident, pri);
	else if (catch)
		rval = sleepq_wait_sig(ident, pri);
	else {
		sleepq_wait(ident, pri);
		rval = 0;
	}
#ifdef KTRACE
	if (KTRPOINT(td, KTR_CSW))
		ktrcsw(0, 0, wmesg);
#endif
	PICKUP_GIANT();
	if (lock != NULL && lock != &Giant.lock_object && !(priority & PDROP)) {
		class->lc_lock(lock, lock_state);
		WITNESS_RESTORE(lock, lock_witness);
	}
	return (rval);
}
int _sleep ( void * ident , struct lock_object * lock , int priority , const char * wmesg , sbintime_t sbt , sbintime_t pr , int flags ) { struct thread * td ; struct proc * p ; struct lock_class * class ; uintptr_t lock_state ; int catch , pri , rval , sleepq_flags ; WITNESS_SAVE_DECL ( lock_witness ) ; td = curthread ; p = td -> td_proc ; #ifdef KTRACE if ( KTRPOINT ( td , KTR_CSW ) ) ktrcsw ( 1 , 0 , wmesg ) ; #endif WITNESS_WARN ( WARN_GIANTOK | WARN_SLEEPOK , lock , " \" \" " , wmesg ) ; KASSERT ( sbt != 0 || mtx_owned ( & Giant ) || lock != NULL , ( " " ) ) ; KASSERT ( p != NULL , ( " " ) ) ; KASSERT ( ident != NULL && TD_IS_RUNNING ( td ) , ( " " ) ) ; if ( priority & PDROP ) KASSERT ( lock != NULL && lock != & Giant . lock_object , ( " " ) ) ; if ( lock != NULL ) class = LOCK_CLASS ( lock ) ; else class = NULL ; if ( SCHEDULER_STOPPED ( ) ) { if ( lock != NULL && priority & PDROP ) class -> lc_unlock ( lock ) ; return ( 0 ) ; } catch = priority & PCATCH ; pri = priority & PRIMASK ; if ( TD_ON_SLEEPQ ( td ) ) sleepq_remove ( td , td -> td_wchan ) ; if ( ( uint8_t * ) ident >= & pause_wchan [ 0 ] && ( uint8_t * ) ident <= & pause_wchan [ MAXCPU - 1 ] ) sleepq_flags = SLEEPQ_PAUSE ; else sleepq_flags = SLEEPQ_SLEEP ; if ( catch ) sleepq_flags |= SLEEPQ_INTERRUPTIBLE ; sleepq_lock ( ident ) ; CTR5 ( KTR_PROC , " " , td -> td_tid , p -> p_pid , td -> td_name , wmesg , ident ) ; if ( lock == & Giant . lock_object ) mtx_assert ( & Giant , MA_OWNED ) ; DROP_GIANT ( ) ; if ( lock != NULL && lock != & Giant . lock_object && ! ( class -> lc_flags & LC_SLEEPABLE ) ) { WITNESS_SAVE ( lock , lock_witness ) ; lock_state = class -> lc_unlock ( lock ) ; } else lock_state = -1 ; sleepq_add ( ident , lock , wmesg , sleepq_flags , 0 ) ; if ( sbt != 0 ) sleepq_set_timeout_sbt ( ident , sbt , pr , flags ) ; if ( lock != NULL && class -> lc_flags & LC_SLEEPABLE ) { sleepq_release ( ident ) ; WITNESS_SAVE ( lock , lock_witness ) ; lock_state = class -> lc_unlock ( lock ) ; sleepq_lock ( ident ) ; } if ( sbt != 0 && catch ) rval = sleepq_timedwait_sig ( ident , pri ) ; else if ( sbt != 0 ) rval = sleepq_timedwait ( ident , pri ) ; else if ( catch ) rval = sleepq_wait_sig ( ident , pri ) ; else { sleepq_wait ( ident , pri ) ; rval = 0 ; } #ifdef KTRACE if ( KTRPOINT ( td , KTR_CSW ) ) ktrcsw ( 0 , 0 , wmesg ) ; #endif PICKUP_GIANT ( ) ; if ( lock != NULL && lock != & Giant . lock_object && ! ( priority & PDROP ) ) { class -> lc_lock ( lock , lock_state ) ; WITNESS_RESTORE ( lock , lock_witness ) ; } return ( rval ) ; }
General sleep call.
General sleep call .
/*
	 * If we are already on a sleep queue, then remove us from that
	 * sleep queue first.  We have to do this to handle recursive
	 * sleeps.
	 */ /* GCC needs to follow the Yellow Brick Road */ /*
	 * We put ourselves on the sleep queue and start our timeout
	 * before calling thread_suspend_check, as we could stop there,
	 * and a wakeup or a SIGCONT (or both) could occur while we were
	 * stopped without resuming us.  Thus, we must be ready for sleep
	 * when cursig() is called.  If the wakeup happens while we're
	 * stopped, then td will no longer be on a sleep queue upon
	 * return from cursig().
	 */