diff options
author | markj <markj@FreeBSD.org> | 2016-12-25 00:35:00 +0000 |
---|---|---|
committer | markj <markj@FreeBSD.org> | 2016-12-25 00:35:00 +0000 |
commit | 8657cfb5865f1bb8f167a2a1b063676ee04d871b (patch) | |
tree | 6ef424767000f5680fbe24cc0f3b871b5b68e0ff /sys/kern/subr_sleepqueue.c | |
parent | 995ede07bde6326c2965be2e4fe39eccd394fa1a (diff) | |
download | FreeBSD-src-8657cfb5865f1bb8f167a2a1b063676ee04d871b.zip FreeBSD-src-8657cfb5865f1bb8f167a2a1b063676ee04d871b.tar.gz |
MFC r310423, r310454:
Revert part of r300109.
Diffstat (limited to 'sys/kern/subr_sleepqueue.c')
-rw-r--r-- | sys/kern/subr_sleepqueue.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index 3f637c6..90c5673 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -880,7 +880,7 @@ int sleepq_broadcast(void *wchan, int flags, int pri, int queue) { struct sleepqueue *sq; - struct thread *td; + struct thread *td, *tdn; int wakeup_swapper; CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags); @@ -892,9 +892,14 @@ sleepq_broadcast(void *wchan, int flags, int pri, int queue) KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE), ("%s: mismatch between sleep/wakeup and cv_*", __func__)); - /* Resume all blocked threads on the sleep queue. */ + /* + * Resume all blocked threads on the sleep queue. 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; - while ((td = TAILQ_FIRST(&sq->sq_blocked[queue])) != NULL) { + TAILQ_FOREACH_SAFE(td, &sq->sq_blocked[queue], td_slpq, tdn) { thread_lock(td); wakeup_swapper |= sleepq_resume_thread(sq, td, pri); thread_unlock(td); |