diff options
author | davidxu <davidxu@FreeBSD.org> | 2006-02-15 23:52:01 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2006-02-15 23:52:01 +0000 |
commit | f1ce5c86603b5f73e31ea323d24ea1433850f704 (patch) | |
tree | 03af904c96a6fe12d7ee078d5642aca586f9f9f0 /sys/kern/kern_condvar.c | |
parent | fc705888e9a61ca2e02d7b2a13ad04491eb844e2 (diff) | |
download | FreeBSD-src-f1ce5c86603b5f73e31ea323d24ea1433850f704.zip FreeBSD-src-f1ce5c86603b5f73e31ea323d24ea1433850f704.tar.gz |
Fix a long standing race between sleep queue and thread
suspension code. When a thread A is going to sleep, it calls
sleepq_catch_signals() to detect any pending signals or thread
suspension request, if nothing happens, it returns without
holding process lock or scheduler lock, this opens a race
window which allows thread B to come in and do process
suspension work, however since A is still at running state,
thread B can do nothing to A, thread A continues, and puts
itself into actually sleeping state, but B has never seen it,
and it sits there forever until B is woken up by other threads
sometimes later(this can be very long delay or never
happen). Fix this bug by forcing sleepq_catch_signals to
return with scheduler lock held.
Fix sleepq_abort() by passing it an interrupted code, previously,
it worked as wakeup_one(), and the interruption can not be
identified correctly by sleep queue code when the sleeping
thread is resumed.
Let thread_suspend_check() returns EINTR or ERESTART, so sleep
queue no longer has to use SIGSTOP as a hack to build a return
value.
Reviewed by: jhb
MFC after: 1 week
Diffstat (limited to 'sys/kern/kern_condvar.c')
-rw-r--r-- | sys/kern/kern_condvar.c | 11 |
1 files changed, 2 insertions, 9 deletions
diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c index ede6b61..f430ea8 100644 --- a/sys/kern/kern_condvar.c +++ b/sys/kern/kern_condvar.c @@ -166,7 +166,7 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp) { struct thread *td; struct proc *p; - int rval, sig; + int rval; WITNESS_SAVE_DECL(mp); td = curthread; @@ -210,10 +210,7 @@ cv_wait_sig(struct cv *cvp, struct mtx *mp) sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR | SLEEPQ_INTERRUPTIBLE); - sig = sleepq_catch_signals(cvp); rval = sleepq_wait_sig(cvp); - if (rval == 0) - rval = sleepq_calc_signal_retval(sig); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) @@ -292,7 +289,6 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) struct thread *td; struct proc *p; int rval; - int sig; WITNESS_SAVE_DECL(mp); td = curthread; @@ -338,10 +334,7 @@ cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR | SLEEPQ_INTERRUPTIBLE); sleepq_set_timeout(cvp, timo); - sig = sleepq_catch_signals(cvp); - rval = sleepq_timedwait_sig(cvp, sig != 0); - if (rval == 0) - rval = sleepq_calc_signal_retval(sig); + rval = sleepq_timedwait_sig(cvp); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) |