Skip to content

Commit 9fb19b5

Browse files
committed
cap catch-up tick iters in skip_and_tick to prevent queue starvation
When the timer thread is suspended for a long time skip_and_tick could loop for tons of iters. We instead cap it so it stays more responsive. The run() loop re-enters immediately and continues catching up on subsequent iterations, so no timer accuracy is permanently lost.
1 parent 2920d2f commit 9fb19b5

1 file changed

Lines changed: 7 additions & 0 deletions

File tree

src/timer.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,9 @@ where
440440
}
441441
}
442442

443+
/// Maximum number of catch-up ticks processed in a single `skip_and_tick` call.
444+
const MAX_CATCH_UP_TICKS: u128 = 1_000;
445+
443446
#[inline(always)]
444447
fn skip_and_tick(&mut self, can_skip: u32, elapsed: u128) {
445448
let can_skip_u128 = can_skip as u128;
@@ -450,12 +453,16 @@ where
450453
// took longer to get rescheduled than we wanted
451454
self.timer.skip(can_skip);
452455
let ticks = elapsed - can_skip_u128;
456+
// cap catch-up iterations per call to avoid starving the message
457+
// queue when the thread was suspended for a long time.
458+
let ticks = ticks.min(Self::MAX_CATCH_UP_TICKS);
453459
for _ in 0..ticks {
454460
self.tick();
455461
}
456462
}
457463
Ordering::Less => {
458464
// we got woken up early, no need to tick
465+
// Safety: elapsed < can_skip (u32), so elapsed fits in u32.
459466
self.timer.skip(elapsed as u32);
460467
}
461468
Ordering::Equal => {

0 commit comments

Comments
 (0)