mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-10-01 12:20:39 +00:00
io: fix possible I/O resource hang (#6134)
Use a per-resource tick instead of a single global tick counter. This prevents the hang issue described by #6133. Fixes: #6133
This commit is contained in:
parent
8ec3e0d94d
commit
30b2eb17c8
@ -18,10 +18,6 @@ use std::time::Duration;
|
|||||||
|
|
||||||
/// I/O driver, backed by Mio.
|
/// I/O driver, backed by Mio.
|
||||||
pub(crate) struct Driver {
|
pub(crate) struct Driver {
|
||||||
/// Tracks the number of times `turn` is called. It is safe for this to wrap
|
|
||||||
/// as it is mostly used to determine when to call `compact()`.
|
|
||||||
tick: u8,
|
|
||||||
|
|
||||||
/// True when an event with the signal token is received
|
/// True when an event with the signal token is received
|
||||||
signal_ready: bool,
|
signal_ready: bool,
|
||||||
|
|
||||||
@ -77,7 +73,7 @@ pub(super) enum Direction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) enum Tick {
|
pub(super) enum Tick {
|
||||||
Set(u8),
|
Set,
|
||||||
Clear(u8),
|
Clear(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +98,6 @@ impl Driver {
|
|||||||
let registry = poll.registry().try_clone()?;
|
let registry = poll.registry().try_clone()?;
|
||||||
|
|
||||||
let driver = Driver {
|
let driver = Driver {
|
||||||
tick: 0,
|
|
||||||
signal_ready: false,
|
signal_ready: false,
|
||||||
events: mio::Events::with_capacity(nevents),
|
events: mio::Events::with_capacity(nevents),
|
||||||
poll,
|
poll,
|
||||||
@ -145,8 +140,6 @@ impl Driver {
|
|||||||
fn turn(&mut self, handle: &Handle, max_wait: Option<Duration>) {
|
fn turn(&mut self, handle: &Handle, max_wait: Option<Duration>) {
|
||||||
debug_assert!(!handle.registrations.is_shutdown(&handle.synced.lock()));
|
debug_assert!(!handle.registrations.is_shutdown(&handle.synced.lock()));
|
||||||
|
|
||||||
self.tick = self.tick.wrapping_add(1);
|
|
||||||
|
|
||||||
handle.release_pending_registrations();
|
handle.release_pending_registrations();
|
||||||
|
|
||||||
let events = &mut self.events;
|
let events = &mut self.events;
|
||||||
@ -184,7 +177,7 @@ impl Driver {
|
|||||||
// an `Arc<ScheduledIo>` so we can safely cast this to a ref.
|
// an `Arc<ScheduledIo>` so we can safely cast this to a ref.
|
||||||
let io: &ScheduledIo = unsafe { &*ptr };
|
let io: &ScheduledIo = unsafe { &*ptr };
|
||||||
|
|
||||||
io.set_readiness(Tick::Set(self.tick), |curr| curr | ready);
|
io.set_readiness(Tick::Set, |curr| curr | ready);
|
||||||
io.wake(ready);
|
io.wake(ready);
|
||||||
|
|
||||||
ready_count += 1;
|
ready_count += 1;
|
||||||
|
@ -219,17 +219,21 @@ impl ScheduledIo {
|
|||||||
let current_readiness = Ready::from_usize(current);
|
let current_readiness = Ready::from_usize(current);
|
||||||
let new = f(current_readiness);
|
let new = f(current_readiness);
|
||||||
|
|
||||||
let next = match tick {
|
let new_tick = match tick {
|
||||||
Tick::Set(t) => TICK.pack(t as usize, new.as_usize()),
|
Tick::Set => {
|
||||||
|
let current = TICK.unpack(current);
|
||||||
|
current.wrapping_add(1) % (TICK.max_value() + 1)
|
||||||
|
}
|
||||||
Tick::Clear(t) => {
|
Tick::Clear(t) => {
|
||||||
if TICK.unpack(current) as u8 != t {
|
if TICK.unpack(current) as u8 != t {
|
||||||
// Trying to clear readiness with an old event!
|
// Trying to clear readiness with an old event!
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TICK.pack(t as usize, new.as_usize())
|
t as usize
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let next = TICK.pack(new_tick, new.as_usize());
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.readiness
|
.readiness
|
||||||
|
Loading…
x
Reference in New Issue
Block a user