diff options
author | kmacy <kmacy@FreeBSD.org> | 2006-12-16 06:54:09 +0000 |
---|---|---|
committer | kmacy <kmacy@FreeBSD.org> | 2006-12-16 06:54:09 +0000 |
commit | 7327d346fcb113617a486207f206df056b5bd56d (patch) | |
tree | 4517eb0f1d912f9b7fa16d26f25614aec2ce42a0 | |
parent | 8cd304e218e3d8dae124070e17be881517d28251 (diff) | |
download | FreeBSD-src-7327d346fcb113617a486207f206df056b5bd56d.zip FreeBSD-src-7327d346fcb113617a486207f206df056b5bd56d.tar.gz |
Add second sleep queue so that sx and lockmgr can have separate sleep
queues for shared and exclusive acquisitions
Submitted by: Attilio Rao
Approved by: jhb
-rw-r--r-- | sys/kern/kern_condvar.c | 14 | ||||
-rw-r--r-- | sys/kern/kern_synch.c | 8 | ||||
-rw-r--r-- | sys/kern/subr_sleepqueue.c | 74 | ||||
-rw-r--r-- | sys/sys/proc.h | 1 | ||||
-rw-r--r-- | sys/sys/sleepqueue.h | 19 |
5 files changed, 71 insertions, 45 deletions
diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c index 85a52b1..e7410e6 100644 --- a/sys/kern/kern_condvar.c +++ b/sys/kern/kern_condvar.c @@ -149,7 +149,8 @@ cv_wait_unlock(struct cv *cvp, struct mtx *mp) DROP_GIANT(); mtx_unlock(mp); - sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR); + sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR, + 0); sleepq_wait(cvp); PICKUP_GIANT(); @@ -197,7 +198,7 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp) mtx_unlock(mp); sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR | - SLEEPQ_INTERRUPTIBLE); + SLEEPQ_INTERRUPTIBLE, 0); rval = sleepq_wait_sig(cvp); #ifdef KTRACE @@ -250,7 +251,8 @@ cv_timedwait(struct cv *cvp, struct mtx *mp, int timo) DROP_GIANT(); mtx_unlock(mp); - sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR); + sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR, + 0); sleepq_set_timeout(cvp, timo); rval = sleepq_timedwait(cvp); @@ -308,7 +310,7 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) mtx_unlock(mp); sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR | - SLEEPQ_INTERRUPTIBLE); + SLEEPQ_INTERRUPTIBLE, 0); sleepq_set_timeout(cvp, timo); rval = sleepq_timedwait_sig(cvp); @@ -337,7 +339,7 @@ cv_signal(struct cv *cvp) sleepq_lock(cvp); if (cvp->cv_waiters > 0) { cvp->cv_waiters--; - sleepq_signal(cvp, SLEEPQ_CONDVAR, -1); + sleepq_signal(cvp, SLEEPQ_CONDVAR, -1, 0); } else sleepq_release(cvp); } @@ -353,7 +355,7 @@ cv_broadcastpri(struct cv *cvp, int pri) sleepq_lock(cvp); if (cvp->cv_waiters > 0) { cvp->cv_waiters = 0; - sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri); + sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0); } else sleepq_release(cvp); } diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 818d7e3..27fd835 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -189,7 +189,7 @@ msleep(ident, mtx, priority, wmesg, timo) * return from cursig(). */ sleepq_add(ident, ident == &lbolt ? NULL : &mtx->mtx_object, wmesg, - flags); + flags, 0); if (timo) sleepq_set_timeout(ident, timo); @@ -267,7 +267,7 @@ msleep_spin(ident, mtx, wmesg, timo) /* * We put ourselves on the sleep queue and start our timeout. */ - sleepq_add(ident, &mtx->mtx_object, wmesg, SLEEPQ_MSLEEP); + sleepq_add(ident, &mtx->mtx_object, wmesg, SLEEPQ_MSLEEP, 0); if (timo) sleepq_set_timeout(ident, timo); @@ -316,7 +316,7 @@ wakeup(ident) { sleepq_lock(ident); - sleepq_broadcast(ident, SLEEPQ_MSLEEP, -1); + sleepq_broadcast(ident, SLEEPQ_MSLEEP, -1, 0); } /* @@ -330,7 +330,7 @@ wakeup_one(ident) { sleepq_lock(ident); - sleepq_signal(ident, SLEEPQ_MSLEEP, -1); + sleepq_signal(ident, SLEEPQ_MSLEEP, -1, 0); } /* diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index 2d79c99..0333665 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -94,7 +94,7 @@ __FBSDID("$FreeBSD$"); #define SC_SHIFT 8 #define SC_HASH(wc) (((uintptr_t)(wc) >> SC_SHIFT) & SC_MASK) #define SC_LOOKUP(wc) &sleepq_chains[SC_HASH(wc)] - +#define NR_SLEEPQS 2 /* * There two different lists of sleep queues. Both lists are connected * via the sq_hash entries. The first list is the sleep queue chain list @@ -114,7 +114,7 @@ __FBSDID("$FreeBSD$"); * c - sleep queue chain lock */ struct sleepqueue { - TAILQ_HEAD(, thread) sq_blocked; /* (c) Blocked threads. */ + TAILQ_HEAD(, thread) sq_blocked[NR_SLEEPQS]; /* (c) Blocked threads. */ LIST_ENTRY(sleepqueue) sq_hash; /* (c) Chain and free list. */ LIST_HEAD(, sleepqueue) sq_free; /* (c) Free queues. */ void *sq_wchan; /* (c) Wait channel. */ @@ -148,6 +148,8 @@ static MALLOC_DEFINE(M_SLEEPQUEUE, "sleepqueue", "sleep queues"); /* * Prototypes for non-exported routines. */ +static int sleepq_catch_signals(void *wchan); +static int sleepq_check_signals(void); static int sleepq_check_timeout(void); static void sleepq_switch(void *wchan); static void sleepq_timeout(void *arg); @@ -192,9 +194,11 @@ struct sleepqueue * sleepq_alloc(void) { struct sleepqueue *sq; + int i; sq = malloc(sizeof(struct sleepqueue), M_SLEEPQUEUE, M_WAITOK | M_ZERO); - TAILQ_INIT(&sq->sq_blocked); + for (i = 0; i < NR_SLEEPQS; i++) + TAILQ_INIT(&sq->sq_blocked[i]); LIST_INIT(&sq->sq_free); return (sq); } @@ -205,9 +209,11 @@ sleepq_alloc(void) void sleepq_free(struct sleepqueue *sq) { + int i; MPASS(sq != NULL); - MPASS(TAILQ_EMPTY(&sq->sq_blocked)); + for (i = 0; i < NR_SLEEPQS; i++) + MPASS(TAILQ_EMPTY(&sq->sq_blocked[i])); free(sq, M_SLEEPQUEUE); } @@ -262,7 +268,8 @@ sleepq_release(void *wchan) * woken up. */ void -sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags) +sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags, + int queue) { struct sleepqueue_chain *sc; struct sleepqueue *sq; @@ -273,6 +280,7 @@ sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags) mtx_assert(&sc->sc_lock, MA_OWNED); MPASS(td->td_sleepqueue != NULL); MPASS(wchan != NULL); + MPASS((queue >= 0) && (queue < NR_SLEEPQS)); /* If this thread is not allowed to sleep, die a horrible death. */ KASSERT(!(td->td_pflags & TDP_NOSLEEPING), @@ -287,6 +295,16 @@ sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags) * into the sleep queue already in use by this wait channel. */ if (sq == NULL) { +#ifdef INVARIANTS + int i; + for (i = 0; i < NR_SLEEP_QUEUEUS; i++) + KASSERT(TAILQ_EMPTY(&sq->sq_blocked[i]), + ("thread's sleep queue %d is not empty", 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")); +#endif #ifdef SLEEPQUEUE_PROFILING sc->sc_depth++; if (sc->sc_depth > sc->sc_max_depth) { @@ -297,11 +315,6 @@ sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags) #endif sq = td->td_sleepqueue; LIST_INSERT_HEAD(&sc->sc_queues, sq, sq_hash); - KASSERT(TAILQ_EMPTY(&sq->sq_blocked), - ("thread's sleep queue has a non-empty queue")); - 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_wchan = wchan; #ifdef INVARIANTS sq->sq_lock = lock; @@ -313,9 +326,10 @@ sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, int flags) MPASS((flags & SLEEPQ_TYPE) == sq->sq_type); LIST_INSERT_HEAD(&sq->sq_free, td->td_sleepqueue, sq_hash); } - TAILQ_INSERT_TAIL(&sq->sq_blocked, td, td_slpq); + TAILQ_INSERT_TAIL(&sq->sq_blocked[queue], td, td_slpq); td->td_sleepqueue = NULL; mtx_lock_spin(&sched_lock); + td->td_sqqueue = queue; td->td_wchan = wchan; td->td_wmesg = wmesg; if (flags & SLEEPQ_INTERRUPTIBLE) { @@ -606,12 +620,13 @@ sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, int pri) MPASS(td != NULL); MPASS(sq->sq_wchan != NULL); MPASS(td->td_wchan == sq->sq_wchan); + MPASS(td->td_sqqueue < NR_SLEEPQS && td->td_sqqueue >= 0); sc = SC_LOOKUP(sq->sq_wchan); mtx_assert(&sc->sc_lock, MA_OWNED); mtx_assert(&sched_lock, MA_OWNED); /* Remove the thread from the queue. */ - TAILQ_REMOVE(&sq->sq_blocked, td, td_slpq); + TAILQ_REMOVE(&sq->sq_blocked[td->td_sqqueue], td, td_slpq); /* * Get a sleep queue for this thread. If this is the last waiter, @@ -656,13 +671,14 @@ sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, int pri) * Find the highest priority thread sleeping on a wait channel and resume it. */ void -sleepq_signal(void *wchan, int flags, int pri) +sleepq_signal(void *wchan, int flags, int pri, int queue) { struct sleepqueue *sq; struct thread *td, *besttd; CTR2(KTR_PROC, "sleepq_signal(%p, %d)", wchan, flags); KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__)); + MPASS((queue >= 0) && (queue < NR_SLEEPQS)); sq = sleepq_lookup(wchan); if (sq == NULL) { sleepq_release(wchan); @@ -678,7 +694,7 @@ sleepq_signal(void *wchan, int flags, int pri) * the tail of sleep queues. */ besttd = NULL; - TAILQ_FOREACH(td, &sq->sq_blocked, td_slpq) { + TAILQ_FOREACH(td, &sq->sq_blocked[queue], td_slpq) { if (besttd == NULL || td->td_priority < besttd->td_priority) besttd = td; } @@ -693,12 +709,13 @@ sleepq_signal(void *wchan, int flags, int pri) * Resume all threads sleeping on a specified wait channel. */ void -sleepq_broadcast(void *wchan, int flags, int pri) +sleepq_broadcast(void *wchan, int flags, int pri, int queue) { struct sleepqueue *sq; CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags); KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__)); + MPASS((queue >= 0) && (queue < NR_SLEEPQS)); sq = sleepq_lookup(wchan); if (sq == NULL) { sleepq_release(wchan); @@ -709,8 +726,9 @@ sleepq_broadcast(void *wchan, int flags, int pri) /* Resume all blocked threads on the sleep queue. */ mtx_lock_spin(&sched_lock); - while (!TAILQ_EMPTY(&sq->sq_blocked)) - sleepq_resume_thread(sq, TAILQ_FIRST(&sq->sq_blocked), pri); + while (!TAILQ_EMPTY(&sq->sq_blocked[queue])) + sleepq_resume_thread(sq, TAILQ_FIRST(&sq->sq_blocked[queue]), + pri); mtx_unlock_spin(&sched_lock); sleepq_release(wchan); } @@ -901,15 +919,19 @@ found: } #endif db_printf("Blocked threads:\n"); - if (TAILQ_EMPTY(&sq->sq_blocked)) - db_printf("\tempty\n"); - else - TAILQ_FOREACH(td, &sq->sq_blocked, td_slpq) { - db_printf("\t%p (tid %d, pid %d, \"%s\")\n", td, - td->td_tid, td->td_proc->p_pid, - td->td_name[0] != '\0' ? td->td_name : - td->td_proc->p_comm); - } + for (i = 0; i < NR_SLEEPQS; i++) { + db_printf("\nQueue[%d]:\n", i); + if (TAILQ_EMPTY(&sq->sq_blocked[i])) + db_printf("\tempty\n"); + else + TAILQ_FOREACH(td, &sq->sq_blocked[0], + td_slpq) { + db_printf("\t%p (tid %d, pid %d, \"%s\")\n", td, + td->td_tid, td->td_proc->p_pid, + td->td_name[i] != '\0' ? td->td_name : + td->td_proc->p_comm); + } + } } /* Alias 'show sleepqueue' to 'show sleepq'. */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index dd19f40..13e41e0 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -235,6 +235,7 @@ struct thread { int td_inhibitors; /* (j) Why can not run. */ int td_pflags; /* (k) Private thread (TDP_*) flags. */ int td_dupfd; /* (k) Ret value from fdopen. XXX */ + int td_sqqueue; /* (j) Sleepqueue queue blocked on. */ void *td_wchan; /* (j) Sleep address. */ const char *td_wmesg; /* (j) Reason for sleep. */ u_char td_lastcpu; /* (j) Last cpu we were on. */ diff --git a/sys/sys/sleepqueue.h b/sys/sys/sleepqueue.h index 0979726..19a231d 100644 --- a/sys/sys/sleepqueue.h +++ b/sys/sys/sleepqueue.h @@ -88,19 +88,20 @@ struct thread; void init_sleepqueues(void); void sleepq_abort(struct thread *td, int intrval); -void sleepq_add(void *, struct lock_object *, const char *, int); +void sleepq_add(void *wchan, struct lock_object *lock, const char *wmesg, + int flags, int queue); struct sleepqueue *sleepq_alloc(void); -void sleepq_broadcast(void *, int, int); -void sleepq_free(struct sleepqueue *); -void sleepq_lock(void *); -struct sleepqueue *sleepq_lookup(void *); -void sleepq_release(void *); -void sleepq_remove(struct thread *, void *); -void sleepq_signal(void *, int, int); +void sleepq_broadcast(void *wchan, int flags, int pri, int queue); +void sleepq_free(struct sleepqueue *sq); +void sleepq_lock(void *wchan); +struct sleepqueue *sleepq_lookup(void *wchan); +void sleepq_release(void *wchan); +void sleepq_remove(struct thread *td, void *wchan); +void sleepq_signal(void *wchan, int flags, int pri, int queue); void sleepq_set_timeout(void *wchan, int timo); int sleepq_timedwait(void *wchan); int sleepq_timedwait_sig(void *wchan); -void sleepq_wait(void *); +void sleepq_wait(void *wchan); int sleepq_wait_sig(void *wchan); #endif /* _KERNEL */ |