Skip to content

Commit 848272d

Browse files
committed
io: fix possible I/O resource hang
Use a per-resource tick instead of a single global tick counter. This prevents the hang issue described by #6133. Fixes: #6133
1 parent 8ec3e0d commit 848272d

File tree

2 files changed

+9
-12
lines changed

2 files changed

+9
-12
lines changed

tokio/src/runtime/io/driver.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ use std::time::Duration;
1818

1919
/// I/O driver, backed by Mio.
2020
pub(crate) struct Driver {
21-
/// Tracks the number of times `turn` is called. It is safe for this to wrap
22-
/// as it is mostly used to determine when to call `compact()`.
23-
tick: u8,
24-
2521
/// True when an event with the signal token is received
2622
signal_ready: bool,
2723

@@ -77,7 +73,7 @@ pub(super) enum Direction {
7773
}
7874

7975
pub(super) enum Tick {
80-
Set(u8),
76+
Set,
8177
Clear(u8),
8278
}
8379

@@ -102,7 +98,6 @@ impl Driver {
10298
let registry = poll.registry().try_clone()?;
10399

104100
let driver = Driver {
105-
tick: 0,
106101
signal_ready: false,
107102
events: mio::Events::with_capacity(nevents),
108103
poll,
@@ -145,8 +140,6 @@ impl Driver {
145140
fn turn(&mut self, handle: &Handle, max_wait: Option<Duration>) {
146141
debug_assert!(!handle.registrations.is_shutdown(&handle.synced.lock()));
147142

148-
self.tick = self.tick.wrapping_add(1);
149-
150143
handle.release_pending_registrations();
151144

152145
let events = &mut self.events;
@@ -184,7 +177,7 @@ impl Driver {
184177
// an `Arc<ScheduledIo>` so we can safely cast this to a ref.
185178
let io: &ScheduledIo = unsafe { &*ptr };
186179

187-
io.set_readiness(Tick::Set(self.tick), |curr| curr | ready);
180+
io.set_readiness(Tick::Set, |curr| curr | ready);
188181
io.wake(ready);
189182

190183
ready_count += 1;

tokio/src/runtime/io/scheduled_io.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,17 +219,21 @@ impl ScheduledIo {
219219
let current_readiness = Ready::from_usize(current);
220220
let new = f(current_readiness);
221221

222-
let next = match tick {
223-
Tick::Set(t) => TICK.pack(t as usize, new.as_usize()),
222+
let new_tick = match tick {
223+
Tick::Set => {
224+
let current = TICK.unpack(current);
225+
current.wrapping_add(1) % TICK.max_value()
226+
}
224227
Tick::Clear(t) => {
225228
if TICK.unpack(current) as u8 != t {
226229
// Trying to clear readiness with an old event!
227230
return;
228231
}
229232

230-
TICK.pack(t as usize, new.as_usize())
233+
t as usize
231234
}
232235
};
236+
let next = TICK.pack(new_tick, new.as_usize());
233237

234238
match self
235239
.readiness

0 commit comments

Comments
 (0)