diff options
Diffstat (limited to 'src/time/wheel/level.rs')
-rw-r--r-- | src/time/wheel/level.rs | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/src/time/wheel/level.rs b/src/time/wheel/level.rs index 8ea30af..4290acf 100644 --- a/src/time/wheel/level.rs +++ b/src/time/wheel/level.rs @@ -140,11 +140,31 @@ impl<T: Stack> Level<T> { // TODO: This can probably be simplified w/ power of 2 math let level_start = now - (now % level_range); - let deadline = level_start + slot as u64 * slot_range; - + let mut deadline = level_start + slot as u64 * slot_range; + if deadline < now { + // A timer is in a slot "prior" to the current time. This can occur + // because we do not have an infinite hierarchy of timer levels, and + // eventually a timer scheduled for a very distant time might end up + // being placed in a slot that is beyond the end of all of the + // arrays. + // + // To deal with this, we first limit timers to being scheduled no + // more than MAX_DURATION ticks in the future; that is, they're at + // most one rotation of the top level away. Then, we force timers + // that logically would go into the top+1 level, to instead go into + // the top level's slots. + // + // What this means is that the top level's slots act as a + // pseudo-ring buffer, and we rotate around them indefinitely. If we + // compute a deadline before now, and it's the top level, it + // therefore means we're actually looking at a slot in the future. + debug_assert_eq!(self.level, super::NUM_LEVELS - 1); + + deadline += level_range; + } debug_assert!( deadline >= now, - "deadline={}; now={}; level={}; slot={}; occupied={:b}", + "deadline={:016X}; now={:016X}; level={}; slot={}; occupied={:b}", deadline, now, self.level, @@ -206,6 +226,10 @@ impl<T: Stack> Level<T> { ret } + + pub(crate) fn peek_entry_slot(&self, slot: usize) -> Option<T::Owned> { + self.slot[slot].peek() + } } impl<T> fmt::Debug for Level<T> { |