summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_sleepqueue.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-01-25 19:44:46 +0000
committerjhb <jhb@FreeBSD.org>2008-01-25 19:44:46 +0000
commitdd3b84ba3a21468b8135cd04a1678c9b216a830f (patch)
tree92b9ee9237f69ae39b34f741f918fed4ea51217c /sys/kern/subr_sleepqueue.c
parente2e2970333e0b30a8ef05ae9dd1807132d521b33 (diff)
downloadFreeBSD-src-dd3b84ba3a21468b8135cd04a1678c9b216a830f.zip
FreeBSD-src-dd3b84ba3a21468b8135cd04a1678c9b216a830f.tar.gz
Fix a bug where a thread that hit the race where the sleep timeout fires
while the thread does not hold the thread lock would stop blocking for subsequent interruptible sleeps and would always immediately fail the sleep with EWOULDBLOCK instead (even sleeps that didn't have a timeout). Some background: - KSE has a facility for allowing one thread to interrupt another thread. During this process, the target thread aborts any interruptible sleeps much as if the target thread had a pending signal. Once the target thread acknowledges the interrupt, normal sleep handling resumes. KSE manages this via the TDF_INTERRUPTED flag. Specifically, it sets the flag when it sends an interrupt to another thread and clears it when the interrupt is acknowledged. (Note that this is purely a software interrupt sort of thing and has no relation to hardware interrupts or kernel interrupt threads.) - The old code for handling the sleep timeout race handled the race by setting the TDF_INTERRUPT flag and faking a KSE-style thread interrupt to the thread in the process of going to sleep. It probably should have just checked the TDF_TIMEOUT flag in sleepq_catch_signals() instead. - The bug was that the sleepq code would set TDF_INTERRUPT but it was never cleared. The sleepq code couldn't safely clear it in case there actually was a real KSE thread interrupt pending for the target thread (in fact, the sleepq timeout actually stomped on said pending interrupt). Thus, any future interruptible sleeps (*sleep(.. PCATCH ..) or cv_*wait_sig()) would see the TDF_INTERRUPT flag set and immediately fail with EWOULDBLOCK. The flag could be cleared if the thread belonged to a KSE process and another thread posted an interrupt to the original thread. However, in the more common case of a non-KSE process, the thread would pretty much stop sleeping. - Fix the bug by just setting TDF_TIMEOUT in the sleepq timeout code and not messing with TDF_INTERRUPT and td_intrval. With yesterday's fix to fix sleepq_switch() to check TDF_TIMEOUT, this is now sufficient. MFC after: 3 days
Diffstat (limited to 'sys/kern/subr_sleepqueue.c')
-rw-r--r--sys/kern/subr_sleepqueue.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c
index 2a95ab6..559278f 100644
--- a/sys/kern/subr_sleepqueue.c
+++ b/sys/kern/subr_sleepqueue.c
@@ -817,8 +817,7 @@ sleepq_timeout(void *arg)
* sleepq_catch_signals().
*/
if (TD_ON_SLEEPQ(td)) {
- td->td_flags |= TDF_TIMEOUT | TDF_INTERRUPT;
- td->td_intrval = EWOULDBLOCK;
+ td->td_flags |= TDF_TIMEOUT;
thread_unlock(td);
return;
}
OpenPOWER on IntegriCloud