summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_condvar.c
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2006-02-15 23:52:01 +0000
committerdavidxu <davidxu@FreeBSD.org>2006-02-15 23:52:01 +0000
commitf1ce5c86603b5f73e31ea323d24ea1433850f704 (patch)
tree03af904c96a6fe12d7ee078d5642aca586f9f9f0 /sys/kern/kern_condvar.c
parentfc705888e9a61ca2e02d7b2a13ad04491eb844e2 (diff)
downloadFreeBSD-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.c11
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))
OpenPOWER on IntegriCloud