aboutsummaryrefslogtreecommitdiff
path: root/src/time/wheel/level.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/time/wheel/level.rs')
-rw-r--r--src/time/wheel/level.rs30
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> {