mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-28 00:00:11 +02:00
Fix race condition in CurrentThread. (#156)
The logic that enables `CurrentThread::turn` to avoid unbounded iteration was incorrect. It was possible for unfortunate timing to result in a dead lock. This patch provides a fix as well as a test.
This commit is contained in:
@@ -202,7 +202,8 @@ where U: Unpark,
|
||||
where F: FnMut(&mut Self, &mut Scheduled<U>),
|
||||
{
|
||||
let mut ret = false;
|
||||
let tick = self.inner.tick_num.fetch_add(1, SeqCst);
|
||||
let tick = self.inner.tick_num.fetch_add(1, SeqCst)
|
||||
.wrapping_add(1);
|
||||
|
||||
loop {
|
||||
let node = match unsafe { self.inner.dequeue(Some(tick)) } {
|
||||
@@ -439,8 +440,18 @@ impl<U> Inner<U> {
|
||||
}
|
||||
|
||||
if let Some(tick) = tick {
|
||||
// Only dequeue if the node matches the tick num
|
||||
if (*tail).notified_at.load(SeqCst) != tick {
|
||||
let actual = (*tail).notified_at.load(SeqCst);
|
||||
|
||||
// Only dequeue if the node was not scheduled during the current
|
||||
// tick.
|
||||
if actual == tick {
|
||||
// Only doing the check above **should** be enough in
|
||||
// practice. However, technically there is a potential for
|
||||
// deadlocking if there are `usize::MAX` ticks while the thread
|
||||
// scheduling the task is frozen.
|
||||
//
|
||||
// If, for some reason, this is not enough, calling `unpark`
|
||||
// here will resolve the issue.
|
||||
return Dequeue::Empty;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -256,7 +256,10 @@ impl Reactor {
|
||||
}
|
||||
|
||||
/// Returns true if the reactor is currently idle.
|
||||
pub(crate) fn is_idle(&self) -> bool {
|
||||
///
|
||||
/// Idle is defined as all tasks that have been spawned have completed,
|
||||
/// either successfully or with an error.
|
||||
pub fn is_idle(&self) -> bool {
|
||||
self.inner.io_dispatch
|
||||
.read().unwrap()
|
||||
.is_empty()
|
||||
@@ -313,9 +316,11 @@ impl Reactor {
|
||||
|
||||
if let Some(io) = io_dispatch.get(token) {
|
||||
io.readiness.fetch_or(ready2usize(ready), Relaxed);
|
||||
|
||||
if ready.is_writable() {
|
||||
io.writer.notify();
|
||||
}
|
||||
|
||||
if !(ready & (!mio::Ready::writable())).is_empty() {
|
||||
io.reader.notify();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user