FreeBSD/sys/kern/subr_sleepqueue.c
/*
 * Places the current thread on the sleep queue for the specified wait
 * channel.  If INVARIANTS is enabled, then it associates the passed in
 * lock with the sleepq to make sure it is held when that sleep queue is
 * woken up.
 */
Places the current thread on the sleep queue for the specified wait
channel.  If INVARIANTS is enabled, then it associates the passed in
lock with the sleepq to make sure it is held when that sleep queue is
woken up.
Places the current thread on the sleep queue for the specified wait channel . If INVARIANTS is enabled then it associates the passed in lock with the sleepq to make sure it is held when that sleep queue is woken up .
void
sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags,
    int queue)
{
	struct sleepqueue_chain *sc;
	struct sleepqueue *sq;
	struct thread *td;
	td = curthread;
	sc = SC_LOOKUP(wchan);
	mtx_assert(&sc->sc_lock, MA_OWNED);
	MPASS(td->td_sleepqueue != NULL);
	MPASS(wchan != NULL);
	MPASS((queue >= 0) && (queue < NR_SLEEPQS));
	KASSERT(td->td_no_sleeping == 0,
	    ("%s: td %p to sleep on wchan %p with sleeping prohibited",
	    __func__, td, wchan));
	sq = sleepq_lookup(wchan);
	if (sq == NULL) {
#ifdef INVARIANTS
		int i;
		sq = td->td_sleepqueue;
		for (i = 0; i < NR_SLEEPQS; i++) {
			KASSERT(TAILQ_EMPTY(&sq->sq_blocked[i]),
			    ("thread's sleep queue %d is not empty", i));
			KASSERT(sq->sq_blockedcnt[i] == 0,
			    ("thread's sleep queue %d count mismatches", i));
		}
		KASSERT(LIST_EMPTY(&sq->sq_free),
		    ("thread's sleep queue has a non-empty free list"));
		KASSERT(sq->sq_wchan == NULL, ("stale sq_wchan pointer"));
		sq->sq_lock = lock;
#endif
#ifdef SLEEPQUEUE_PROFILING
		sc->sc_depth++;
		if (sc->sc_depth > sc->sc_max_depth) {
			sc->sc_max_depth = sc->sc_depth;
			if (sc->sc_max_depth > sleepq_max_depth)
				sleepq_max_depth = sc->sc_max_depth;
		}
#endif
		sq = td->td_sleepqueue;
		LIST_INSERT_HEAD(&sc->sc_queues, sq, sq_hash);
		sq->sq_wchan = wchan;
		sq->sq_type = flags & SLEEPQ_TYPE;
	} else {
		MPASS(wchan == sq->sq_wchan);
		MPASS(lock == sq->sq_lock);
		MPASS((flags & SLEEPQ_TYPE) == sq->sq_type);
		LIST_INSERT_HEAD(&sq->sq_free, td->td_sleepqueue, sq_hash);
	}
	thread_lock(td);
	TAILQ_INSERT_TAIL(&sq->sq_blocked[queue], td, td_slpq);
	sq->sq_blockedcnt[queue]++;
	td->td_sleepqueue = NULL;
	td->td_sqqueue = queue;
	td->td_wchan = wchan;
	td->td_wmesg = wmesg;
	if (flags & SLEEPQ_INTERRUPTIBLE) {
		td->td_flags |= TDF_SINTR;
		td->td_flags &= ~TDF_SLEEPABORT;
	}
	thread_unlock(td);
}
void sleepq_add ( void * wchan , struct lock_object * lock , const char * wmesg , int flags , int queue ) { struct sleepqueue_chain * sc ; struct sleepqueue * sq ; struct thread * td ; td = curthread ; sc = SC_LOOKUP ( wchan ) ; mtx_assert ( & sc -> sc_lock , MA_OWNED ) ; MPASS ( td -> td_sleepqueue != NULL ) ; MPASS ( wchan != NULL ) ; MPASS ( ( queue >= 0 ) && ( queue < NR_SLEEPQS ) ) ; KASSERT ( td -> td_no_sleeping == 0 , ( " " , __func__ , td , wchan ) ) ; sq = sleepq_lookup ( wchan ) ; if ( sq == NULL ) { #ifdef INVARIANTS int i ; sq = td -> td_sleepqueue ; for ( i = 0 ; i < NR_SLEEPQS ; i ++ ) { KASSERT ( TAILQ_EMPTY ( & sq -> sq_blocked [ i ] ) , ( " " , i ) ) ; KASSERT ( sq -> sq_blockedcnt [ i ] == 0 , ( " " , i ) ) ; } KASSERT ( LIST_EMPTY ( & sq -> sq_free ) , ( " " ) ) ; KASSERT ( sq -> sq_wchan == NULL , ( " " ) ) ; sq -> sq_lock = lock ; #endif #ifdef SLEEPQUEUE_PROFILING sc -> sc_depth ++ ; if ( sc -> sc_depth > sc -> sc_max_depth ) { sc -> sc_max_depth = sc -> sc_depth ; if ( sc -> sc_max_depth > sleepq_max_depth ) sleepq_max_depth = sc -> sc_max_depth ; } #endif sq = td -> td_sleepqueue ; LIST_INSERT_HEAD ( & sc -> sc_queues , sq , sq_hash ) ; sq -> sq_wchan = wchan ; sq -> sq_type = flags & SLEEPQ_TYPE ; } else { MPASS ( wchan == sq -> sq_wchan ) ; MPASS ( lock == sq -> sq_lock ) ; MPASS ( ( flags & SLEEPQ_TYPE ) == sq -> sq_type ) ; LIST_INSERT_HEAD ( & sq -> sq_free , td -> td_sleepqueue , sq_hash ) ; } thread_lock ( td ) ; TAILQ_INSERT_TAIL ( & sq -> sq_blocked [ queue ] , td , td_slpq ) ; sq -> sq_blockedcnt [ queue ] ++ ; td -> td_sleepqueue = NULL ; td -> td_sqqueue = queue ; td -> td_wchan = wchan ; td -> td_wmesg = wmesg ; if ( flags & SLEEPQ_INTERRUPTIBLE ) { td -> td_flags |= TDF_SINTR ; td -> td_flags &= ~ TDF_SLEEPABORT ; } thread_unlock ( td ) ; }
Places the current thread on the sleep queue for the specified wait
 channel.
Places the current thread on the sleep queue for the specified wait channel .
/* If this thread is not allowed to sleep, die a horrible death. */ /* Look up the sleep queue associated with the wait channel 'wchan'. */ /*
	 * If the wait channel does not already have a sleep queue, use
	 * this thread's sleep queue.  Otherwise, insert the current thread
	 * into the sleep queue already in use by this wait channel.
	 */