diff options
author | davidxu <davidxu@FreeBSD.org> | 2006-02-23 00:13:58 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2006-02-23 00:13:58 +0000 |
commit | e29c8e080b595587aafe2e1d02c5eb9f9f322a51 (patch) | |
tree | 7e38ae2e71791b901f46413e77ea39d2b4ba7ae0 /sys | |
parent | ff94f53a5d7abb067a90f6013082aaa99474583d (diff) | |
download | FreeBSD-src-e29c8e080b595587aafe2e1d02c5eb9f9f322a51.zip FreeBSD-src-e29c8e080b595587aafe2e1d02c5eb9f9f322a51.tar.gz |
Fix a sleep queue race for KSE thread.
Reviewed by: jhb
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_condvar.c | 24 | ||||
-rw-r--r-- | sys/kern/kern_synch.c | 22 | ||||
-rw-r--r-- | sys/kern/subr_sleepqueue.c | 32 |
3 files changed, 25 insertions, 53 deletions
diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c index f430ea8..7377981 100644 --- a/sys/kern/kern_condvar.c +++ b/sys/kern/kern_condvar.c @@ -192,18 +192,6 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp) sleepq_lock(cvp); - /* - * Don't bother sleeping if we are exiting and not the exiting - * thread or if our thread is marked as interrupted. - */ - mtx_lock_spin(&sched_lock); - rval = thread_sleep_check(td); - mtx_unlock_spin(&sched_lock); - if (rval != 0) { - sleepq_release(cvp); - return (rval); - } - cvp->cv_waiters++; DROP_GIANT(); mtx_unlock(mp); @@ -315,18 +303,6 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) sleepq_lock(cvp); - /* - * Don't bother sleeping if we are exiting and not the exiting - * thread or if our thread is marked as interrupted. - */ - mtx_lock_spin(&sched_lock); - rval = thread_sleep_check(td); - mtx_unlock_spin(&sched_lock); - if (rval != 0) { - sleepq_release(cvp); - return (rval); - } - cvp->cv_waiters++; DROP_GIANT(); mtx_unlock(mp); diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index f988946..d2c6acc 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -164,22 +164,11 @@ msleep(ident, mtx, priority, wmesg, timo) if (TD_ON_SLEEPQ(td)) sleepq_remove(td, td->td_wchan); + flags = SLEEPQ_MSLEEP; + if (catch) + flags |= SLEEPQ_INTERRUPTIBLE; + sleepq_lock(ident); - if (catch) { - /* - * Don't bother sleeping if we are exiting and not the exiting - * thread or if our thread is marked as interrupted. - */ - mtx_lock_spin(&sched_lock); - rval = thread_sleep_check(td); - mtx_unlock_spin(&sched_lock); - if (rval != 0) { - sleepq_release(ident); - if (mtx != NULL && priority & PDROP) - mtx_unlock(mtx); - return (rval); - } - } CTR5(KTR_PROC, "msleep: thread %p (pid %ld, %s) on %s (%p)", (void *)td, (long)p->p_pid, p->p_comm, wmesg, ident); @@ -199,9 +188,6 @@ msleep(ident, mtx, priority, wmesg, timo) * stopped, then td will no longer be on a sleep queue upon * return from cursig(). */ - flags = SLEEPQ_MSLEEP; - if (catch) - flags |= SLEEPQ_INTERRUPTIBLE; sleepq_add(ident, mtx, wmesg, flags); if (timo) sleepq_set_timeout(ident, timo); diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index 464cf28..c269806 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -387,23 +387,33 @@ sleepq_catch_signals(void *wchan) mtx_unlock(&ps->ps_mtx); } - if (ret) { - PROC_UNLOCK(p); + if (ret == 0) { + mtx_lock_spin(&sc->sc_lock); /* - * If there were pending signals and this thread is still on - * the sleep queue, remove it from the sleep queue. + * Lock sched_lock before unlocking proc lock, + * without this, we could lose a race. */ - mtx_lock_spin(&sc->sc_lock); - sq = sleepq_lookup(wchan); mtx_lock_spin(&sched_lock); - if (TD_ON_SLEEPQ(td)) - sleepq_resume_thread(sq, td, -1); - td->td_flags &= ~TDF_SINTR; + PROC_UNLOCK(p); + if (!(td->td_flags & TDF_INTERRUPT)) + return (0); + /* KSE threads tried unblocking us. */ + ret = td->td_intrval; + mtx_unlock_spin(&sched_lock); + MPASS(ret == EINTR || ret == ERESTART); } else { - mtx_lock_spin(&sc->sc_lock); - mtx_lock_spin(&sched_lock); PROC_UNLOCK(p); + /* + * If there were pending signals and this thread is still + * on the sleep queue, remove it from the sleep queue. + */ + mtx_lock_spin(&sc->sc_lock); } + sq = sleepq_lookup(wchan); + mtx_lock_spin(&sched_lock); + if (TD_ON_SLEEPQ(td)) + sleepq_resume_thread(sq, td, -1); + td->td_flags &= ~TDF_SINTR; return (ret); } |