Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/subr_sleepqueue.c
Show First 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <sys/sched.h> | #include <sys/sched.h> | ||||
#include <sys/sdt.h> | #include <sys/sdt.h> | ||||
#include <sys/signalvar.h> | #include <sys/signalvar.h> | ||||
#include <sys/sleepqueue.h> | #include <sys/sleepqueue.h> | ||||
#include <sys/stack.h> | #include <sys/stack.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/time.h> | |||||
#include <machine/atomic.h> | |||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
#ifdef DDB | #ifdef DDB | ||||
#include <ddb/ddb.h> | #include <ddb/ddb.h> | ||||
#endif | #endif | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 444 Lines • ▼ Show 20 Lines | |||||
* Returns with thread lock. | * Returns with thread lock. | ||||
*/ | */ | ||||
static void | static void | ||||
sleepq_switch(void *wchan, int pri) | sleepq_switch(void *wchan, int pri) | ||||
{ | { | ||||
struct sleepqueue_chain *sc; | struct sleepqueue_chain *sc; | ||||
struct sleepqueue *sq; | struct sleepqueue *sq; | ||||
struct thread *td; | struct thread *td; | ||||
bool rtc_changed; | |||||
td = curthread; | td = curthread; | ||||
sc = SC_LOOKUP(wchan); | sc = SC_LOOKUP(wchan); | ||||
mtx_assert(&sc->sc_lock, MA_OWNED); | mtx_assert(&sc->sc_lock, MA_OWNED); | ||||
THREAD_LOCK_ASSERT(td, MA_OWNED); | THREAD_LOCK_ASSERT(td, MA_OWNED); | ||||
/* | /* | ||||
* If we have a sleep queue, then we've already been woken up, so | * If we have a sleep queue, then we've already been woken up, so | ||||
* just return. | * just return. | ||||
*/ | */ | ||||
if (td->td_sleepqueue != NULL) { | if (td->td_sleepqueue != NULL) { | ||||
mtx_unlock_spin(&sc->sc_lock); | mtx_unlock_spin(&sc->sc_lock); | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* If TDF_TIMEOUT is set, then our sleep has been timed out | * If TDF_TIMEOUT is set, then our sleep has been timed out | ||||
* already but we are still on the sleep queue, so dequeue the | * already but we are still on the sleep queue, so dequeue the | ||||
* thread and return. | * thread and return. Do the same if the real-time clock has | ||||
* been adjusted since this thread calculated its timeout | |||||
* based on that clock. | |||||
*/ | */ | ||||
if (td->td_flags & TDF_TIMEOUT) { | rtc_changed = td->td_rtcgen != 0 && td->td_rtcgen != rtc_generation; | ||||
if ((td->td_flags & TDF_TIMEOUT) || rtc_changed) { | |||||
if (rtc_changed) { | |||||
td->td_rtcgen = 0; | |||||
} | |||||
MPASS(TD_ON_SLEEPQ(td)); | MPASS(TD_ON_SLEEPQ(td)); | ||||
sq = sleepq_lookup(wchan); | sq = sleepq_lookup(wchan); | ||||
if (sleepq_resume_thread(sq, td, 0)) { | if (sleepq_resume_thread(sq, td, 0)) { | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
/* | /* | ||||
* This thread hasn't gone to sleep yet, so it | * This thread hasn't gone to sleep yet, so it | ||||
* should not be swapped out. | * should not be swapped out. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 310 Lines • ▼ Show 20 Lines | sleepq_signal(void *wchan, int flags, int pri, int queue) | ||||
} | } | ||||
MPASS(besttd != NULL); | MPASS(besttd != NULL); | ||||
thread_lock(besttd); | thread_lock(besttd); | ||||
wakeup_swapper = sleepq_resume_thread(sq, besttd, pri); | wakeup_swapper = sleepq_resume_thread(sq, besttd, pri); | ||||
thread_unlock(besttd); | thread_unlock(besttd); | ||||
return (wakeup_swapper); | return (wakeup_swapper); | ||||
} | } | ||||
static bool | |||||
match_any(struct thread *td __unused) | |||||
{ | |||||
return (true); | |||||
} | |||||
/* | /* | ||||
* Resume all threads sleeping on a specified wait channel. | * Resume all threads sleeping on a specified wait channel. | ||||
*/ | */ | ||||
int | int | ||||
sleepq_broadcast(void *wchan, int flags, int pri, int queue) | sleepq_broadcast(void *wchan, int flags, int pri, int queue) | ||||
{ | { | ||||
struct sleepqueue *sq; | struct sleepqueue *sq; | ||||
struct thread *td, *tdn; | |||||
int wakeup_swapper; | |||||
CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags); | CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags); | ||||
KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__)); | KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__)); | ||||
MPASS((queue >= 0) && (queue < NR_SLEEPQS)); | MPASS((queue >= 0) && (queue < NR_SLEEPQS)); | ||||
sq = sleepq_lookup(wchan); | sq = sleepq_lookup(wchan); | ||||
if (sq == NULL) | if (sq == NULL) | ||||
return (0); | return (0); | ||||
KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE), | KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE), | ||||
("%s: mismatch between sleep/wakeup and cv_*", __func__)); | ("%s: mismatch between sleep/wakeup and cv_*", __func__)); | ||||
return (sleepq_remove_matching(sq, queue, match_any, pri)); | |||||
} | |||||
/* | /* | ||||
* Resume all blocked threads on the sleep queue. The last thread will | * Resume threads on the sleep queue that match the given predicate. | ||||
* be given ownership of sq and may re-enqueue itself before | |||||
* sleepq_resume_thread() returns, so we must cache the "next" queue | |||||
* item at the beginning of the final iteration. | |||||
*/ | */ | ||||
int | |||||
sleepq_remove_matching(struct sleepqueue *sq, int queue, | |||||
bool (*matches)(struct thread *), int pri) | |||||
{ | |||||
struct thread *td, *tdn; | |||||
int wakeup_swapper; | |||||
/* | |||||
* The last thread will be given ownership of sq and may | |||||
* re-enqueue itself before sleepq_resume_thread() returns, | |||||
* so we must cache the "next" queue item at the beginning | |||||
* of the final iteration. | |||||
*/ | |||||
wakeup_swapper = 0; | wakeup_swapper = 0; | ||||
TAILQ_FOREACH_SAFE(td, &sq->sq_blocked[queue], td_slpq, tdn) { | TAILQ_FOREACH_SAFE(td, &sq->sq_blocked[queue], td_slpq, tdn) { | ||||
thread_lock(td); | thread_lock(td); | ||||
if (matches(td)) | |||||
wakeup_swapper |= sleepq_resume_thread(sq, td, pri); | wakeup_swapper |= sleepq_resume_thread(sq, td, pri); | ||||
thread_unlock(td); | thread_unlock(td); | ||||
} | } | ||||
return (wakeup_swapper); | return (wakeup_swapper); | ||||
} | } | ||||
/* | /* | ||||
* Time sleeping threads out. When the timeout expires, the thread is | * Time sleeping threads out. When the timeout expires, the thread is | ||||
* removed from the sleep queue and made runnable if it is still asleep. | * removed from the sleep queue and made runnable if it is still asleep. | ||||
*/ | */ | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | if (!TD_IS_SLEEPING(td)) | ||||
return (0); | return (0); | ||||
wchan = td->td_wchan; | wchan = td->td_wchan; | ||||
MPASS(wchan != NULL); | MPASS(wchan != NULL); | ||||
sq = sleepq_lookup(wchan); | sq = sleepq_lookup(wchan); | ||||
MPASS(sq != NULL); | MPASS(sq != NULL); | ||||
/* Thread is asleep on sleep queue sq, so wake it up. */ | /* Thread is asleep on sleep queue sq, so wake it up. */ | ||||
return (sleepq_resume_thread(sq, td, 0)); | return (sleepq_resume_thread(sq, td, 0)); | ||||
} | |||||
void | |||||
sleepq_chains_remove_matching(bool (*matches)(struct thread *)) | |||||
{ | |||||
struct sleepqueue_chain *sc; | |||||
struct sleepqueue *sq; | |||||
int i, wakeup_swapper; | |||||
wakeup_swapper = 0; | |||||
for (sc = &sleepq_chains[0]; sc < sleepq_chains + SC_TABLESIZE; ++sc) { | |||||
if (LIST_EMPTY(&sc->sc_queues)) { | |||||
continue; | |||||
} | |||||
mtx_lock_spin(&sc->sc_lock); | |||||
LIST_FOREACH(sq, &sc->sc_queues, sq_hash) { | |||||
for (i = 0; i < NR_SLEEPQS; ++i) { | |||||
wakeup_swapper |= sleepq_remove_matching(sq, i, | |||||
matches, 0); | |||||
} | |||||
} | |||||
mtx_unlock_spin(&sc->sc_lock); | |||||
} | |||||
if (wakeup_swapper) { | |||||
kick_proc0(); | |||||
} | |||||
} | } | ||||
/* | /* | ||||
* Prints the stacks of all threads presently sleeping on wchan/queue to | * Prints the stacks of all threads presently sleeping on wchan/queue to | ||||
* the sbuf sb. Sets count_stacks_printed to the number of stacks actually | * the sbuf sb. Sets count_stacks_printed to the number of stacks actually | ||||
* printed. Typically, this will equal the number of threads sleeping on the | * printed. Typically, this will equal the number of threads sleeping on the | ||||
* queue, but may be less if sb overflowed before all stacks were printed. | * queue, but may be less if sb overflowed before all stacks were printed. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 322 Lines • Show Last 20 Lines |