Skip to main content

ntex_util/time/
wheel.rs

1//! Hierarchical timer wheel backing ntex timers.
2//!
3//! The design follows the Linux kernel timer wheel (`kernel/time/timer.c`).
4//!
5//! # Clock
6//!
7//! The wheel counts time in *units* of 16 milliseconds (`1 << UNITS`). The
8//! wheel clock `elapsed` is the unit of the last processed expiry, and
9//! `elapsed_time` is the [`Instant`] that corresponds to it. Timer deadlines
10//! are converted to units relative to this pair.
11//!
12//! # Levels
13//!
14//! The wheel has `LVL_DEPTH` (8) levels of `LVL_SIZE` (64) buckets. Each level
15//! is 8 times coarser than the previous one, a timer is placed on the first
16//! level that can represent its delay:
17//!
18//! | Level | Granularity | Range            |
19//! |-------|-------------|------------------|
20//! | 0     | 16 ms       | 0 .. ~1 s        |
21//! | 1     | 128 ms      | ~1 s .. ~8 s     |
22//! | 2     | ~1 s        | ~8 s .. ~64 s    |
23//! | 3     | ~8 s        | ~64 s .. ~8.6 m  |
24//! | 4     | ~65 s       | ~8.6 m .. ~69 m  |
25//! | 5     | ~8.7 m      | ~69 m .. ~9.2 h  |
26//! | 6     | ~70 m       | ~9.2 h .. ~3 d   |
27//! | 7     | ~9.3 h      | ~3 d .. ~24.5 d  |
28//!
29//! Longer delays are clamped to the capacity of the wheel. The expiry is
30//! rounded up to the granularity of the level and the delay is measured from
31//! [`Instant::now()`], so a timer never fires early but may fire up to one
32//! granularity late. Timers are not cascaded to finer
33//! levels, which keeps insertion and removal `O(1)`.
34//!
35//! A bitmap per level tracks occupied buckets, the next expiry is found by
36//! scanning the bitmaps instead of the buckets.
37//!
38//! # Drivers
39//!
40//! Two tasks are spawned lazily on the current thread:
41//!
42//! * [`TimerDriver`] sleeps until the next occupied bucket expires and wakes
43//!   the timers stored in it. The clock advances to the scheduled time of the
44//!   bucket, not to the time the driver woke up, so a late wakeup does not
45//!   delay later timers. Buckets that are overdue are processed at once.
46//!   Wakers are invoked in place while the wheel is held; timer operations
47//!   are not reentrant. Callback timers are queued separately and invoked
48//!   after releasing the wheel.
49//! * [`LowresTimerDriver`] invalidates the cached [`system_time()`] value
50//!   every 150 milliseconds.
51//!
52//! Dropping the timer driver, i.e. when the runtime stops, stops the wheel and
53//! marks all timers as elapsed. Dropping the lowres driver invalidates the
54//! cached system time.
55//!
56//! A runtime does not always drop its pending tasks when it stops, the timer
57//! is also reset once the arbiter storage of the stopped system is cleared,
58//! so that the next runtime on the thread starts its own drivers. Drivers of
59//! an older generation exit without touching the state.
60//!
61//! Registrations retain owned [`ntex_rt::LocalWaker`] handles, specializing
62//! native owner-thread wakes without allocating wrappers or growing entries.
63//! Standard wakers are still accepted at polling boundaries.
64use std::num::NonZeroUsize;
65use std::time::{Duration, Instant, SystemTime};
66use std::{cell::Cell, cmp, future::Future, mem, pin::Pin, rc::Rc, task, task::Poll};
67
68use futures_timer::Delay;
69use slab::Slab;
70
71use super::callbacks::Callbacks;
72use crate::task::LocalWaker;
73
74/// Resolution of the wheel clock, a unit is `1 << UNITS` milliseconds.
75const UNITS: u64 = 4;
76
77/// Each level is `LVL_CLK_DIV` times coarser than the previous one.
78const LVL_CLK_SHIFT: u64 = 3;
79const LVL_CLK_DIV: u64 = 1 << LVL_CLK_SHIFT;
80const LVL_CLK_MASK: u64 = LVL_CLK_DIV - 1;
81
82/// Number of buckets per level.
83const LVL_BITS: u64 = 6;
84const LVL_SIZE: u64 = 1 << LVL_BITS;
85const LVL_MASK: u64 = LVL_SIZE - 1;
86
87/// Number of levels.
88const LVL_DEPTH: u64 = 8;
89
90/// Total number of buckets.
91const WHEEL_SIZE: usize = (LVL_SIZE * LVL_DEPTH) as usize;
92
93/// Delays at or above the cutoff are clamped to `WHEEL_TIMEOUT_MAX`.
94const WHEEL_TIMEOUT_CUTOFF: u64 = lvl_start(LVL_DEPTH);
95const WHEEL_TIMEOUT_MAX: u64 = WHEEL_TIMEOUT_CUTOFF - lvl_gran(LVL_DEPTH - 1);
96
97/// Refresh interval of the cached time.
98const LOWRES_RESOLUTION: Duration = Duration::from_millis(150);
99
100/// Shift of the level clock relative to the wheel clock.
101const fn lvl_shift(lvl: u64) -> u64 {
102    lvl * LVL_CLK_SHIFT
103}
104
105/// Granularity of a level in units.
106const fn lvl_gran(lvl: u64) -> u64 {
107    1 << lvl_shift(lvl)
108}
109
110/// Smallest delay in units that is stored on level `lvl`, `lvl` must be at
111/// least 1.
112const fn lvl_start(lvl: u64) -> u64 {
113    (LVL_SIZE - 1) << ((lvl - 1) * LVL_CLK_SHIFT)
114}
115
116const fn to_units(millis: u64) -> u64 {
117    millis >> UNITS
118}
119
120const fn to_millis(units: u64) -> u64 {
121    units << UNITS
122}
123
124const fn as_millis(dur: Duration) -> u64 {
125    dur.as_secs() * 1_000 + (dur.subsec_millis() as u64)
126}
127
128/// Returns the start of the current runtime turn, see [`ntex_rt::now()`].
129///
130/// Tasks polled in the same turn observe the same instant on neon and compio,
131/// on tokio this is [`Instant::now()`].
132#[inline]
133pub fn now() -> Instant {
134    ntex_rt::now()
135}
136
137/// Returns a cached approximation of the current system time.
138///
139/// The cached value is refreshed at roughly 150 millisecond intervals.
140#[inline]
141pub fn system_time() -> SystemTime {
142    TIMER.with(Timer::system_time)
143}
144
145#[derive(Debug)]
146/// Handle to a timer registered with ntex's local timer wheel.
147///
148/// Dropping the handle cancels the timer. A handle may be reset and reused
149/// after it has elapsed.
150///
151/// Timer operations are not reentrant. Registered wakers must not synchronously
152/// access the timer wheel when cloned, woken or dropped.
153pub struct TimerHandle(NonZeroUsize);
154
155impl TimerHandle {
156    /// Registers a timer that elapses after `millis`.
157    pub fn new(millis: u64) -> Self {
158        TIMER.with(|t| t.add_timer(millis))
159    }
160
161    /// Restarts the timer with a new delay in milliseconds.
162    pub fn reset(&self, millis: u64) {
163        TIMER.with(|t| t.update_timer(self.0.get(), millis));
164    }
165
166    /// Completes the timer immediately and wakes its registered task.
167    pub fn elapse(&self) {
168        TIMER.with(|t| t.remove_timer(self.0.get()));
169    }
170
171    /// Returns `true` if this timer has elapsed.
172    pub fn is_elapsed(&self) -> bool {
173        TIMER.with(|t| t.with_wheel(|w| w.timers[self.0.get()].bucket.is_none()))
174    }
175
176    /// Polls until this timer has elapsed.
177    pub fn poll_elapsed(&self, cx: &mut task::Context<'_>) -> Poll<()> {
178        TIMER.with(|t| {
179            t.with_wheel(|w| {
180                let entry = &mut w.timers[self.0.get()];
181                if entry.bucket.is_none() {
182                    Poll::Ready(())
183                } else {
184                    if entry.task.as_ref().is_none_or(|w| !w.will_wake(cx.waker())) {
185                        entry.task = Some(ntex_rt::LocalWaker::from_waker(cx.waker()));
186                    }
187                    Poll::Pending
188                }
189            })
190        })
191    }
192}
193
194impl Drop for TimerHandle {
195    fn drop(&mut self) {
196        // the wheel is already destroyed if the handle is dropped by
197        // another thread-local destructor
198        let _ = TIMER.try_with(|t| {
199            t.with_wheel(|w| {
200                w.unlink(self.0.get());
201                w.timers.remove(self.0.get());
202            });
203        });
204    }
205}
206
207bitflags::bitflags! {
208    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
209    struct Flags: u8 {
210        /// The timer driver task is spawned.
211        const DRIVER_STARTED = 0b0000_0001;
212        /// The cached time is populated and its refresh sleep is armed.
213        const LOWRES_TIMER   = 0b0000_1000;
214        /// The lowres driver task is spawned.
215        const LOWRES_DRIVER  = 0b0001_0000;
216        /// A timer was scheduled, `system_time()` caches the time.
217        const RUNNING        = 0b0010_0000;
218    }
219}
220
221thread_local! {
222    pub(super) static TIMER: Rc<Timer> = Rc::new(Timer::new());
223}
224
225/// Per-thread timer state, shared by the timer handles and the driver tasks.
226pub(super) struct Timer {
227    /// Wheel clock in units, the expiry that was processed last.
228    elapsed: Cell<u64>,
229    /// Instant that corresponds to `elapsed`, the scheduled time of the last
230    /// processed expiry. Set lazily when the wheel is idle.
231    elapsed_time: Cell<Option<Instant>>,
232    /// Expiry of the earliest occupied bucket, `u64::MAX` if the wheel is empty.
233    next_expiry: Cell<u64>,
234    flags: Cell<Flags>,
235    /// Incremented on reset, drivers of an older generation are stale.
236    pub(super) generation: Cell<u64>,
237    driver: LocalWaker,
238    lowres_stime: Cell<Option<SystemTime>>,
239    lowres_driver: LocalWaker,
240    /// Taken out of the cell for the duration of an operation.
241    wheel: Cell<Option<Box<Wheel>>>,
242}
243
244/// Timer storage.
245pub(super) struct Wheel {
246    /// Timer entries indexed by handle, slot 0 is reserved so handles are
247    /// non-zero.
248    pub(super) timers: Slab<TimerEntry>,
249    /// Handles of the timers stored in each bucket, `lvl * LVL_SIZE + offset`.
250    buckets: Box<[Slab<usize>]>,
251    /// Occupied buckets of each level, bit `n` is set if bucket `n` has timers.
252    occupied: [u64; LVL_DEPTH as usize],
253    /// Allocated only for callbacks, keeping ordinary entries waker-sized.
254    pub(super) callbacks: Option<Box<Callbacks>>,
255}
256
257struct WheelGuard<'a> {
258    slot: &'a Cell<Option<Box<Wheel>>>,
259    wheel: Option<Box<Wheel>>,
260}
261
262impl Drop for WheelGuard<'_> {
263    fn drop(&mut self) {
264        self.slot.set(self.wheel.take());
265    }
266}
267
268#[derive(Debug)]
269pub(super) struct TimerEntry {
270    /// Bucket index, `None` once the timer has elapsed.
271    pub(super) bucket: Option<u16>,
272    /// Key of the entry in the bucket.
273    pub(super) bucket_entry: usize,
274    pub(super) callback: bool,
275    pub(super) task: Option<ntex_rt::LocalWaker>,
276}
277
278#[cfg(target_pointer_width = "64")]
279const _: () = assert!(mem::size_of::<TimerEntry>() == 32);
280
281struct ExpiredTimers<'a> {
282    timers: &'a mut Slab<TimerEntry>,
283    entries: slab::Drain<'a, usize>,
284}
285
286impl Drop for ExpiredTimers<'_> {
287    fn drop(&mut self) {
288        // A panicking wake must not leave entries pointing into a drained bucket.
289        for no in self.entries.by_ref() {
290            self.timers[no].bucket = None;
291        }
292    }
293}
294
295impl Timer {
296    fn new() -> Self {
297        let mut timers = Slab::default();
298        timers.insert(TimerEntry {
299            bucket: None,
300            bucket_entry: 0,
301            callback: false,
302            task: None,
303        });
304
305        Timer {
306            elapsed: Cell::new(0),
307            elapsed_time: Cell::new(None),
308            next_expiry: Cell::new(u64::MAX),
309            flags: Cell::new(Flags::empty()),
310            generation: Cell::new(0),
311            driver: LocalWaker::new(),
312            lowres_stime: Cell::new(None),
313            lowres_driver: LocalWaker::new(),
314            wheel: Cell::new(Some(Box::new(Wheel {
315                timers,
316                buckets: (0..WHEEL_SIZE).map(|_| Slab::new()).collect(),
317                occupied: [0; LVL_DEPTH as usize],
318                callbacks: None,
319            }))),
320        }
321    }
322
323    pub(super) fn with_wheel<F, R>(&self, f: F) -> R
324    where
325        F: FnOnce(&mut Wheel) -> R,
326    {
327        let mut guard = WheelGuard {
328            slot: &self.wheel,
329            wheel: Some(
330                self.wheel
331                    .take()
332                    .expect("timer wheel operations are not reentrant"),
333            ),
334        };
335        f(guard.wheel.as_deref_mut().unwrap())
336    }
337
338    fn insert_flags(&self, flags: Flags) -> Flags {
339        let mut f = self.flags.get();
340        f.insert(flags);
341        self.flags.set(f);
342        f
343    }
344
345    /// Returns the cached system time, the cache is populated only while the
346    /// wheel is running.
347    fn system_time(self: &Rc<Self>) -> SystemTime {
348        if let Some(cur) = self.lowres_stime.get() {
349            cur
350        } else {
351            let now = SystemTime::now();
352            if self.flags.get().contains(Flags::RUNNING) {
353                self.lowres_stime.set(Some(now));
354                self.refresh_lowres();
355            }
356            now
357        }
358    }
359
360    /// Arms the invalidation of the cached time.
361    fn refresh_lowres(self: &Rc<Self>) {
362        if self.flags.get().contains(Flags::LOWRES_DRIVER) {
363            self.lowres_driver.wake();
364        } else {
365            LowresTimerDriver::start(self);
366        }
367    }
368
369    /// Instant that corresponds to the wheel clock.
370    fn elapsed_time(&self) -> Instant {
371        if let Some(elapsed_time) = self.elapsed_time.get() {
372            elapsed_time
373        } else {
374            let elapsed_time = Instant::now();
375            self.elapsed_time.set(Some(elapsed_time));
376            elapsed_time
377        }
378    }
379
380    fn add_timer(self: &Rc<Self>, millis: u64) -> TimerHandle {
381        let no = if millis == 0 {
382            // elapsed immediately
383            self.with_wheel(|w| {
384                w.timers.insert(TimerEntry {
385                    bucket: None,
386                    bucket_entry: 0,
387                    callback: false,
388                    task: None,
389                })
390            })
391        } else {
392            let (idx, expiry) = self.calc_bucket(millis);
393            let no = self.with_wheel(|w| {
394                let no = w.timers.insert(TimerEntry {
395                    bucket: None,
396                    bucket_entry: 0,
397                    callback: false,
398                    task: None,
399                });
400                w.link(no, idx);
401                no
402            });
403            self.update_next_expiry(expiry);
404            no
405        };
406
407        // slot 0 is reserved in `Timer::new()`
408        TimerHandle(NonZeroUsize::new(no).unwrap())
409    }
410
411    /// Moves the timer to a new bucket, a zero delay elapses it and wakes its
412    /// task.
413    fn update_timer(self: &Rc<Self>, hnd: usize, millis: u64) {
414        if millis == 0 {
415            self.remove_timer(hnd);
416        } else {
417            let (idx, expiry) = self.calc_bucket(millis);
418            self.with_wheel(|w| w.relink(hnd, idx));
419            self.update_next_expiry(expiry);
420        }
421    }
422
423    /// Elapses the timer and wakes its task.
424    fn remove_timer(&self, hnd: usize) {
425        self.with_wheel(|w| {
426            if w.unlink(hnd)
427                && let Some(task) = w.timers[hnd].task.take()
428            {
429                task.wake();
430            }
431        });
432    }
433
434    /// Returns the bucket index and the bucket expiry for a delay starting now.
435    pub(super) fn calc_bucket(self: &Rc<Self>, millis: u64) -> (usize, u64) {
436        self.insert_flags(Flags::RUNNING);
437
438        // The delay is measured from the wheel clock. The cached time is not
439        // used, it goes stale while the thread is blocked and the timer would
440        // fire early by its age
441        let since = Instant::now().saturating_duration_since(self.elapsed_time());
442        let delta = to_units(as_millis(since) + millis);
443        self.calc_wheel_index(self.elapsed.get().wrapping_add(delta), delta)
444    }
445
446    /// Selects the level for a timer that expires at `expires`, `delta` units
447    /// from now.
448    fn calc_wheel_index(&self, expires: u64, delta: u64) -> (usize, u64) {
449        for lvl in 0..LVL_DEPTH {
450            if delta < lvl_start(lvl + 1) {
451                return Self::calc_index(expires, lvl);
452            }
453        }
454        // expire larger delays at the capacity limit of the wheel
455        Self::calc_index(
456            self.elapsed.get().wrapping_add(WHEEL_TIMEOUT_MAX),
457            LVL_DEPTH - 1,
458        )
459    }
460
461    /// Returns the bucket index and the bucket expiry on level `lvl`.
462    fn calc_index(expires: u64, lvl: u64) -> (usize, u64) {
463        // The timer must not fire early. Early expiry can happen because the
464        // timer is armed at the edge of a tick, or because the expiry is
465        // truncated to the level granularity, round up to prevent it.
466        let expires = (expires + lvl_gran(lvl)) >> lvl_shift(lvl);
467        (
468            (lvl * LVL_SIZE + (expires & LVL_MASK)) as usize,
469            expires << lvl_shift(lvl),
470        )
471    }
472
473    /// Wakes the driver if the new bucket expires before the current deadline.
474    pub(super) fn update_next_expiry(self: &Rc<Self>, expiry: u64) {
475        if expiry < self.next_expiry.get() {
476            self.next_expiry.set(expiry);
477            if self.flags.get().contains(Flags::DRIVER_STARTED) {
478                self.driver.wake();
479            } else {
480                TimerDriver::start(self);
481            }
482        }
483    }
484
485    /// Instant at which the bucket expiring at `expiry` is due.
486    fn expiry_time(&self, expiry: u64) -> Instant {
487        self.elapsed_time()
488            + Duration::from_millis(to_millis(expiry.saturating_sub(self.elapsed.get())))
489    }
490
491    /// Returns the expiry of the earliest occupied bucket.
492    fn next_pending_bucket(&self, wheel: &Wheel) -> Option<u64> {
493        let mut clk = self.elapsed.get();
494        let mut next = u64::MAX;
495
496        for lvl in 0..LVL_DEPTH {
497            let lvl_clk = clk & LVL_CLK_MASK;
498            let occupied = wheel.occupied[lvl as usize];
499
500            if occupied != 0 {
501                // distance to the next occupied bucket, wrapping around the level
502                let pos = u64::from(
503                    occupied
504                        .rotate_right((clk & LVL_MASK) as u32)
505                        .trailing_zeros(),
506                );
507                next = cmp::min(next, (clk + pos) << lvl_shift(lvl));
508
509                // The next level is reached once the clock of this level wraps
510                // to a multiple of `LVL_CLK_DIV`, an earlier bucket here cannot
511                // be preceded by one of the next level.
512                if pos <= ((LVL_CLK_DIV - lvl_clk) & LVL_CLK_MASK) {
513                    break;
514                }
515            }
516
517            // Clock of the next level. A partially elapsed tick of this level
518            // is rounded up, as the next level bucket it belongs to was already
519            // processed.
520            clk >>= LVL_CLK_SHIFT;
521            clk += u64::from(lvl_clk != 0);
522        }
523
524        if next < u64::MAX { Some(next) } else { None }
525    }
526
527    /// Removes `flags`, and `RUNNING` so the cached time is not populated and
528    /// no driver is spawned after the runtime stopped.
529    fn remove_flags(&self, flags: Flags) {
530        let mut f = self.flags.get();
531        f.remove(flags | Flags::RUNNING);
532        self.flags.set(f);
533    }
534
535    /// Invalidates the cached time, called when the lowres driver is dropped.
536    fn stop_lowres(&self) {
537        self.remove_flags(Flags::LOWRES_DRIVER | Flags::LOWRES_TIMER);
538        self.lowres_stime.set(None);
539    }
540
541    /// Stops the drivers of the current generation, called when the system
542    /// that runs them has stopped.
543    fn reset(&self) {
544        self.generation.set(self.generation.get().wrapping_add(1));
545        self.stop_wheel();
546        self.stop_lowres();
547        self.driver.take_local();
548        self.lowres_driver.take_local();
549    }
550
551    /// Marks all timers as elapsed and resets the wheel, called when the timer
552    /// driver is dropped. Tasks are not woken, the runtime is stopping.
553    fn stop_wheel(&self) {
554        self.remove_flags(Flags::DRIVER_STARTED);
555
556        self.with_wheel(|wheel| {
557            let Wheel {
558                timers,
559                buckets,
560                occupied,
561                callbacks,
562            } = wheel;
563            for bucket in buckets.iter_mut() {
564                for no in bucket.drain() {
565                    timers[no].bucket = None;
566                }
567            }
568            *occupied = [0; LVL_DEPTH as usize];
569            if let Some(callbacks) = callbacks {
570                callbacks.ready.clear();
571                for ticket in callbacks.entries.values() {
572                    if let Some(state) = ticket.state.upgrade() {
573                        state.pending.set(false);
574                    }
575                }
576            }
577
578            self.next_expiry.set(u64::MAX);
579            self.elapsed.set(0);
580            self.elapsed_time.set(None);
581        });
582    }
583}
584
585impl Wheel {
586    /// Level and occupied bit of a bucket.
587    fn bucket_bit(idx: usize) -> (usize, u64) {
588        (idx / LVL_SIZE as usize, 1 << (idx % LVL_SIZE as usize))
589    }
590
591    /// Stores the timer in bucket `idx`.
592    pub(super) fn link(&mut self, hnd: usize, idx: usize) {
593        let entry = &mut self.timers[hnd];
594        entry.bucket = Some(idx as u16);
595        entry.bucket_entry = self.buckets[idx].insert(hnd);
596
597        let (lvl, bit) = Self::bucket_bit(idx);
598        self.occupied[lvl] |= bit;
599    }
600
601    /// Removes the timer from its bucket and marks it as elapsed.
602    ///
603    /// Returns `false` if the timer has already elapsed.
604    pub(super) fn unlink(&mut self, hnd: usize) -> bool {
605        let entry = &mut self.timers[hnd];
606        if let Some(idx) = entry.bucket.take() {
607            let idx = idx as usize;
608            let bucket = &mut self.buckets[idx];
609            bucket.remove(entry.bucket_entry);
610            if bucket.is_empty() {
611                let (lvl, bit) = Self::bucket_bit(idx);
612                self.occupied[lvl] &= !bit;
613            }
614            true
615        } else {
616            false
617        }
618    }
619
620    /// Moves the timer to bucket `idx`.
621    pub(super) fn relink(&mut self, hnd: usize, idx: usize) {
622        if self.timers[hnd].bucket != Some(idx as u16) {
623            self.unlink(hnd);
624            self.link(hnd, idx);
625        }
626    }
627
628    /// Marks timers elapsed, waking tasks in place and queueing only callbacks.
629    fn execute_expired_timers(&mut self, mut clk: u64) {
630        for lvl in 0..LVL_DEPTH {
631            let idx = ((clk & LVL_MASK) + lvl * LVL_SIZE) as usize;
632            let bucket = &mut self.buckets[idx];
633            if !bucket.is_empty() {
634                let (lvl, bit) = Self::bucket_bit(idx);
635                self.occupied[lvl] &= !bit;
636                let mut expired = ExpiredTimers {
637                    timers: &mut self.timers,
638                    entries: bucket.drain(),
639                };
640                for no in expired.entries.by_ref() {
641                    let entry = &mut expired.timers[no];
642                    entry.bucket = None;
643                    if entry.callback {
644                        let callbacks = self.callbacks.as_mut().unwrap();
645                        callbacks.ready.push(callbacks.entries[&no].clone());
646                    } else if let Some(task) = entry.task.take() {
647                        task.wake();
648                    }
649                }
650            }
651
652            // The next level expires only when the clock is a multiple of its
653            // granularity
654            if (clk & LVL_CLK_MASK) != 0 {
655                break;
656            }
657            clk >>= LVL_CLK_SHIFT;
658        }
659    }
660}
661
662/// Resets the timer when dropped with the arbiter storage of a stopped system.
663#[derive(Default)]
664struct TimerReset;
665
666impl TimerReset {
667    fn register() {
668        ntex_rt::with_item::<TimerReset, _, _>(|_| ());
669    }
670}
671
672impl Drop for TimerReset {
673    fn drop(&mut self) {
674        // the timer is already destroyed if the thread is exiting
675        let _ = TIMER.try_with(|t| t.reset());
676    }
677}
678
679/// Task that sleeps until the next bucket expires and wakes its timers.
680struct TimerDriver {
681    timer: Rc<Timer>,
682    generation: u64,
683    sleep: Delay,
684    /// Deadline the sleep is armed for.
685    armed: Option<Instant>,
686}
687
688impl TimerDriver {
689    fn start(timer: &Rc<Timer>) {
690        timer.insert_flags(Flags::DRIVER_STARTED);
691        TimerReset::register();
692
693        let deadline = timer.expiry_time(timer.next_expiry.get());
694        crate::spawn_detached(TimerDriver {
695            timer: timer.clone(),
696            generation: timer.generation.get(),
697            sleep: Delay::new(deadline.saturating_duration_since(Instant::now())),
698            armed: Some(deadline),
699        });
700    }
701}
702
703impl Drop for TimerDriver {
704    fn drop(&mut self) {
705        if self.timer.generation.get() == self.generation {
706            self.timer.stop_wheel();
707        }
708    }
709}
710
711impl Future for TimerDriver {
712    type Output = ();
713
714    fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
715        let this = &mut *self;
716        let timer = &this.timer;
717        if timer.generation.get() != this.generation {
718            return Poll::Ready(());
719        }
720        timer.driver.register(cx.waker());
721
722        let mut now = Instant::now();
723
724        loop {
725            let expiry = timer.next_expiry.get();
726            if expiry == u64::MAX {
727                // the wheel is empty, a new timer wakes the driver
728                return Poll::Pending;
729            }
730
731            let deadline = timer.expiry_time(expiry);
732            if deadline > now {
733                if this.armed != Some(deadline) {
734                    this.armed = Some(deadline);
735                    this.sleep.reset(deadline.saturating_duration_since(now));
736                }
737                if Pin::new(&mut this.sleep).poll(cx).is_pending() {
738                    return Poll::Pending;
739                }
740                if deadline > now {
741                    // the sleep fired before the deadline, re-arm it
742                    this.armed = None;
743                    continue;
744                }
745            }
746
747            // Advance the clock to the scheduled time of the bucket, a late
748            // wakeup must not shift the timers that expire later
749            timer.elapsed.set(expiry);
750            timer.elapsed_time.set(Some(deadline));
751
752            let (next, callbacks) = timer.with_wheel(|w| {
753                w.execute_expired_timers(expiry);
754                let callbacks = w.callbacks.as_mut().and_then(|callbacks| {
755                    if callbacks.ready.is_empty() {
756                        None
757                    } else {
758                        Some(mem::take(&mut callbacks.ready))
759                    }
760                });
761                (timer.next_pending_bucket(w), callbacks)
762            });
763
764            if let Some(next) = next {
765                timer.next_expiry.set(next);
766            } else {
767                timer.next_expiry.set(u64::MAX);
768                timer.elapsed_time.set(None);
769            }
770
771            if let Some(mut callbacks) = callbacks {
772                for ticket in callbacks.drain(..) {
773                    if timer.generation.get() != this.generation {
774                        return Poll::Ready(());
775                    }
776                    if ticket.generation == this.generation
777                        && let Some(state) = ticket.state.upgrade()
778                        && state.arm.get() == ticket.arm
779                        && state.pending.replace(false)
780                    {
781                        (state.callback)();
782                    }
783                }
784                // A callback or its captures may have stopped this runtime.
785                if timer.generation.get() != this.generation {
786                    return Poll::Ready(());
787                }
788                timer.with_wheel(|wheel| wheel.callbacks.as_mut().unwrap().ready = callbacks);
789                now = Instant::now();
790            }
791        }
792    }
793}
794
795/// Task that invalidates the cached time every `LOWRES_RESOLUTION`.
796struct LowresTimerDriver {
797    timer: Rc<Timer>,
798    generation: u64,
799    sleep: Delay,
800}
801
802impl LowresTimerDriver {
803    fn start(timer: &Rc<Timer>) {
804        timer.insert_flags(Flags::LOWRES_DRIVER);
805        TimerReset::register();
806
807        crate::spawn_detached(LowresTimerDriver {
808            timer: timer.clone(),
809            generation: timer.generation.get(),
810            sleep: Delay::new(LOWRES_RESOLUTION),
811        });
812    }
813}
814
815impl Drop for LowresTimerDriver {
816    fn drop(&mut self) {
817        if self.timer.generation.get() == self.generation {
818            self.timer.stop_lowres();
819        }
820    }
821}
822
823impl Future for LowresTimerDriver {
824    type Output = ();
825
826    fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
827        let this = &mut *self;
828        let timer = &this.timer;
829        if timer.generation.get() != this.generation {
830            return Poll::Ready(());
831        }
832        timer.lowres_driver.register(cx.waker());
833
834        // the cache was populated, invalidate it after `LOWRES_RESOLUTION`
835        let mut flags = timer.flags.get();
836        if !flags.contains(Flags::LOWRES_TIMER) {
837            flags.insert(Flags::LOWRES_TIMER);
838            timer.flags.set(flags);
839            this.sleep.reset(LOWRES_RESOLUTION);
840        }
841
842        if Pin::new(&mut this.sleep).poll(cx).is_ready() {
843            timer.lowres_stime.set(None);
844            flags.remove(Flags::LOWRES_TIMER);
845            timer.flags.set(flags);
846        }
847        Poll::Pending
848    }
849}
850
851#[cfg(test)]
852mod tests {
853    use std::cell::RefCell;
854    use std::panic::{AssertUnwindSafe, catch_unwind};
855    use std::sync::Arc;
856    use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
857    use std::task::{Context, RawWaker, RawWakerVTable, Wake, Waker};
858
859    use super::*;
860    use crate::future::OnDropFn;
861    use crate::time::{CallbackTimer, Millis, interval, sleep};
862
863    #[derive(Default)]
864    struct InPlaceWaker {
865        wakes: AtomicUsize,
866        delay: Duration,
867        panic_on_wake: bool,
868    }
869
870    impl Wake for InPlaceWaker {
871        fn wake(self: Arc<Self>) {
872            TIMER.with(|timer| {
873                let wheel = timer.wheel.take();
874                let held = wheel.is_none();
875                timer.wheel.set(wheel);
876                assert!(held, "waker must run in place while the wheel is held");
877            });
878            let previous = self.wakes.fetch_add(1, Ordering::Relaxed);
879            assert!(!self.panic_on_wake, "notification");
880            if previous == 0 && !self.delay.is_zero() {
881                std::thread::sleep(self.delay);
882            }
883        }
884    }
885
886    fn timer_state() -> Rc<Timer> {
887        TIMER.with(|timer| {
888            timer.reset();
889            // These tests drive expiry manually, without an executor.
890            timer.insert_flags(Flags::DRIVER_STARTED);
891            timer.clone()
892        })
893    }
894
895    fn timer_driver(timer: &Rc<Timer>) -> TimerDriver {
896        TimerDriver {
897            timer: timer.clone(),
898            generation: timer.generation.get(),
899            sleep: Delay::new(Duration::ZERO),
900            armed: None,
901        }
902    }
903
904    fn make_due(timer: &Timer) {
905        timer.elapsed_time.set(Some(
906            Instant::now().checked_sub(Duration::from_secs(1)).unwrap(),
907        ));
908    }
909
910    #[derive(Debug)]
911    struct NoopNotify;
912
913    impl ntex_rt::Notify for NoopNotify {
914        fn notify(&self) -> std::io::Result<()> {
915            Ok(())
916        }
917    }
918
919    #[test]
920    fn test_local_waker_registration() {
921        struct Registration {
922            inner: Waker,
923            clones: AtomicUsize,
924            panic_on_clone: AtomicBool,
925        }
926
927        // Keep clone identity stable without relying on generic vtable deduplication.
928        static VTABLE: RawWakerVTable = RawWakerVTable::new(
929            |data| unsafe {
930                let state = &*data.cast::<Registration>();
931                assert!(!state.panic_on_clone.load(Ordering::Relaxed), "clone");
932                state.clones.fetch_add(1, Ordering::Relaxed);
933                Arc::increment_strong_count(data.cast::<Registration>());
934                RawWaker::new(data, &VTABLE)
935            },
936            |data| unsafe {
937                Arc::from_raw(data.cast::<Registration>())
938                    .inner
939                    .wake_by_ref();
940            },
941            |data| unsafe {
942                (*data.cast::<Registration>()).inner.wake_by_ref();
943            },
944            |data| unsafe {
945                drop(Arc::from_raw(data.cast::<Registration>()));
946            },
947        );
948
949        let wrap = |task: &Arc<InPlaceWaker>| {
950            let state = Arc::new(Registration {
951                inner: Waker::from(task.clone()),
952                clones: AtomicUsize::new(0),
953                panic_on_clone: AtomicBool::new(false),
954            });
955            let waker = unsafe {
956                Waker::from_raw(RawWaker::new(Arc::into_raw(state.clone()).cast(), &VTABLE))
957            };
958            (state, waker)
959        };
960
961        let timer = timer_state();
962        let handle = TimerHandle::new(10_000);
963        let old_task = Arc::new(InPlaceWaker::default());
964        let new_task = Arc::new(InPlaceWaker::default());
965        let (old, old_waker) = wrap(&old_task);
966        let (new, new_waker) = wrap(&new_task);
967        let mut old_cx = Context::from_waker(&old_waker);
968        let mut new_cx = Context::from_waker(&new_waker);
969
970        assert!(handle.poll_elapsed(&mut old_cx).is_pending());
971        handle.reset(20_000);
972        assert!(handle.poll_elapsed(&mut old_cx).is_pending());
973        assert_eq!(old.clones.load(Ordering::Relaxed), 1);
974        assert_eq!(Arc::strong_count(&old), 3);
975
976        new.panic_on_clone.store(true, Ordering::Relaxed);
977        assert!(catch_unwind(AssertUnwindSafe(|| handle.poll_elapsed(&mut new_cx))).is_err());
978        timer.with_wheel(|wheel| {
979            assert!(
980                wheel.timers[handle.0.get()]
981                    .task
982                    .as_ref()
983                    .unwrap()
984                    .will_wake(&old_waker)
985            );
986        });
987        assert_eq!(Arc::strong_count(&old), 3);
988        assert_eq!(Arc::strong_count(&new), 2);
989
990        new.panic_on_clone.store(false, Ordering::Relaxed);
991        assert!(handle.poll_elapsed(&mut new_cx).is_pending());
992        assert!(handle.poll_elapsed(&mut new_cx).is_pending());
993        assert_eq!(new.clones.load(Ordering::Relaxed), 1);
994        assert_eq!(Arc::strong_count(&old), 2);
995        assert_eq!(Arc::strong_count(&new), 3);
996
997        timer.with_wheel(|wheel| {
998            wheel.relink(handle.0.get(), 3);
999            wheel.execute_expired_timers(3);
1000        });
1001        assert!(handle.poll_elapsed(&mut new_cx).is_ready());
1002        assert_eq!(new.clones.load(Ordering::Relaxed), 1);
1003        assert_eq!(new_task.wakes.load(Ordering::Relaxed), 1);
1004        assert_eq!(old_task.wakes.load(Ordering::Relaxed), 0);
1005        assert_eq!(Arc::strong_count(&new), 2);
1006
1007        handle.reset(10_000);
1008        assert!(handle.poll_elapsed(&mut old_cx).is_pending());
1009        handle.reset(0);
1010        assert!(handle.is_elapsed());
1011        assert_eq!(old_task.wakes.load(Ordering::Relaxed), 1);
1012        assert_eq!(Arc::strong_count(&old), 2);
1013
1014        handle.reset(10_000);
1015        assert!(handle.poll_elapsed(&mut old_cx).is_pending());
1016        drop(handle);
1017        assert_eq!(old_task.wakes.load(Ordering::Relaxed), 1);
1018        assert_eq!(old.clones.load(Ordering::Relaxed), 3);
1019        assert_eq!(Arc::strong_count(&old), 2);
1020    }
1021
1022    #[test]
1023    fn test_local_waker_native_replacement() {
1024        let timer = timer_state();
1025        let rt = ntex_rt::Runtime::new(Box::new(NoopNotify));
1026        let handle = Rc::new(TimerHandle::new(10_000));
1027        let first_waker = Rc::new(Cell::new(None));
1028        let (first_handle, saved) = (handle.clone(), first_waker.clone());
1029        let first = rt.spawn(std::future::poll_fn(move |cx| {
1030            saved.set(Some(cx.waker().clone()));
1031            first_handle.poll_elapsed(cx)
1032        }));
1033        rt.poll();
1034
1035        let second_handle = handle.clone();
1036        let second = rt.spawn(std::future::poll_fn(move |cx| {
1037            second_handle.poll_elapsed(cx)
1038        }));
1039        rt.poll();
1040        timer.with_wheel(|wheel| {
1041            wheel.relink(handle.0.get(), 3);
1042            wheel.execute_expired_timers(3);
1043        });
1044        rt.poll();
1045        assert!(!first.is_finished());
1046        assert!(second.is_finished());
1047
1048        handle.reset(10_000);
1049        first_waker.take().unwrap().wake();
1050        rt.poll();
1051        assert!(!first.is_finished());
1052        handle.reset(0);
1053        rt.poll();
1054        assert!(first.is_finished());
1055        assert_eq!(Rc::strong_count(&handle), 1);
1056        drop(rt);
1057        first_waker.take().unwrap().wake();
1058    }
1059
1060    #[test]
1061    fn test_local_waker_runtime_shutdown() {
1062        for reuse in [false, true] {
1063            let timer = timer_state();
1064            let rt = ntex_rt::Runtime::new(Box::new(NoopNotify));
1065            let handle = Rc::new(TimerHandle::new(10_000));
1066            let (task_timer, task_handle) = (timer.clone(), handle.clone());
1067            let task = rt.spawn(std::future::poll_fn(move |cx| {
1068                task_timer.driver.register(cx.waker());
1069                task_timer.lowres_driver.register(cx.waker());
1070                task_handle.poll_elapsed(cx)
1071            }));
1072            rt.poll();
1073            drop(rt);
1074            assert!(task.is_finished());
1075            assert_eq!(Rc::strong_count(&handle), 1);
1076            drop(task);
1077
1078            timer.reset();
1079            assert!(handle.is_elapsed());
1080            assert!(!timer.driver.is_set());
1081            assert!(!timer.lowres_driver.is_set());
1082            timer.with_wheel(|wheel| {
1083                assert!(wheel.timers[handle.0.get()].task.is_some());
1084            });
1085
1086            if reuse {
1087                timer.insert_flags(Flags::DRIVER_STARTED);
1088                handle.reset(10_000);
1089                let rt = ntex_rt::Runtime::new(Box::new(NoopNotify));
1090                let task_handle = handle.clone();
1091                let task = rt.spawn(std::future::poll_fn(move |cx| task_handle.poll_elapsed(cx)));
1092                rt.poll();
1093                assert!(!task.is_finished());
1094                handle.elapse();
1095                rt.poll();
1096                assert!(task.is_finished());
1097                assert_eq!(Rc::strong_count(&handle), 1);
1098            }
1099            drop(handle);
1100            timer.with_wheel(|wheel| assert_eq!(wheel.timers.len(), 1));
1101        }
1102    }
1103
1104    #[test]
1105    fn test_local_waker_in_next_system() {
1106        struct Wrapped {
1107            inner: Waker,
1108            wakes: Arc<AtomicUsize>,
1109        }
1110
1111        impl Wake for Wrapped {
1112            fn wake(self: Arc<Self>) {
1113                self.wakes.fetch_add(1, Ordering::Relaxed);
1114                self.inner.wake_by_ref();
1115            }
1116        }
1117
1118        std::thread::spawn(|| {
1119            let mut handle = None::<TimerHandle>;
1120            for wrapped in [false, true, false] {
1121                let notifications = Arc::new(AtomicUsize::new(0));
1122                let count = notifications.clone();
1123                handle = Some(
1124                    ntex::rt::System::build()
1125                        .build(ntex::rt::DefaultRuntime)
1126                        .block_on(async move {
1127                            let handle = if let Some(handle) = handle {
1128                                assert!(handle.is_elapsed());
1129                                handle.reset(10_000);
1130                                handle
1131                            } else {
1132                                TimerHandle::new(10_000)
1133                            };
1134                            std::future::poll_fn(|cx| {
1135                                let waker = if wrapped {
1136                                    Waker::from(Arc::new(Wrapped {
1137                                        inner: cx.waker().clone(),
1138                                        wakes: count.clone(),
1139                                    }))
1140                                } else {
1141                                    cx.waker().clone()
1142                                };
1143                                let cx = &mut Context::from_waker(&waker);
1144                                assert!(handle.poll_elapsed(cx).is_pending());
1145                                handle.reset(0);
1146                                assert!(handle.poll_elapsed(cx).is_ready());
1147                                handle.reset(10_000);
1148                                assert!(handle.poll_elapsed(cx).is_pending());
1149                                Poll::Ready(())
1150                            })
1151                            .await;
1152                            handle
1153                        }),
1154                );
1155                assert!(handle.as_ref().unwrap().is_elapsed());
1156                assert_eq!(notifications.load(Ordering::Relaxed), usize::from(wrapped));
1157            }
1158        })
1159        .join()
1160        .unwrap();
1161    }
1162
1163    #[ntex::test]
1164    async fn test_callback_timer() {
1165        let calls = Rc::new(Cell::new(0));
1166        let count = calls.clone();
1167        let callback = crate::time::CallbackTimer::new(Millis::ZERO, move || {
1168            count.set(count.get() + 1);
1169        });
1170        assert!(!callback.is_elapsed());
1171        assert_eq!(calls.get(), 0);
1172        callback.reset(Millis(10_000));
1173        callback.cancel();
1174        assert!(callback.is_elapsed());
1175        sleep(Millis(50)).await;
1176        assert_eq!(calls.get(), 0);
1177
1178        for expected in 1..=2 {
1179            callback.reset(Millis::ZERO);
1180            assert!(!callback.is_elapsed());
1181            sleep(Millis(50)).await;
1182            assert!(callback.is_elapsed());
1183            assert_eq!(calls.get(), expected);
1184        }
1185    }
1186
1187    #[test]
1188    fn test_callback_stale_tickets() {
1189        let timer = timer_state();
1190        let calls = Rc::new(Cell::new(0));
1191        let count = calls.clone();
1192        let cancelled = CallbackTimer::new(Millis(1), move || count.set(count.get() + 1));
1193        let count = calls.clone();
1194        let reset = CallbackTimer::new(Millis(1), move || count.set(count.get() + 1));
1195        let capture = Rc::new(Cell::new(0));
1196        let weak = Rc::downgrade(&capture);
1197        let dropped = CallbackTimer::new(Millis(1), move || capture.set(1));
1198        let old_slot = dropped.hnd;
1199        timer.with_wheel(|wheel| {
1200            for handle in [&cancelled, &reset, &dropped] {
1201                wheel.relink(handle.hnd.get(), 3);
1202            }
1203            wheel.execute_expired_timers(3);
1204        });
1205        assert!(cancelled.is_elapsed());
1206        assert!(reset.is_elapsed());
1207        assert!(dropped.is_elapsed());
1208        assert_eq!(calls.get(), 0);
1209        cancelled.cancel();
1210        reset.reset(Millis(10_000));
1211        drop(dropped);
1212        assert!(
1213            weak.upgrade().is_none(),
1214            "queued tickets must not retain captures"
1215        );
1216        let count = calls.clone();
1217        let replacement = CallbackTimer::new(Millis(10_000), move || count.set(count.get() + 100));
1218        assert_eq!(replacement.hnd, old_slot);
1219
1220        make_due(&timer);
1221        let mut driver = timer_driver(&timer);
1222        assert!(
1223            Pin::new(&mut driver)
1224                .poll(&mut Context::from_waker(Waker::noop()))
1225                .is_pending()
1226        );
1227        assert_eq!(calls.get(), 0);
1228        assert!(!reset.is_elapsed());
1229        assert!(!replacement.is_elapsed());
1230        timer.elapsed_time.set(Some(
1231            Instant::now().checked_sub(Duration::from_secs(20)).unwrap(),
1232        ));
1233        for _ in 0..2 {
1234            assert!(
1235                Pin::new(&mut driver)
1236                    .poll(&mut Context::from_waker(Waker::noop()))
1237                    .is_pending()
1238            );
1239            assert_eq!(calls.get(), 101);
1240        }
1241    }
1242
1243    #[test]
1244    fn test_callback_self_rearm_and_cross_cancel() {
1245        let timer = timer_state();
1246        let calls = Rc::new(Cell::new(0));
1247        let handles = Rc::new(RefCell::new(Vec::<CallbackTimer>::new()));
1248        for index in 0..2 {
1249            let count = calls.clone();
1250            let weak = Rc::downgrade(&handles);
1251            let callback = CallbackTimer::new(Millis(1), move || {
1252                count.set(count.get() + 1);
1253                let handles = weak.upgrade().unwrap();
1254                let handles = handles.borrow();
1255                assert!(handles[index].is_elapsed());
1256                handles[1 - index].cancel();
1257                handles[index].reset(Millis(10_000));
1258            });
1259            handles.borrow_mut().push(callback);
1260        }
1261        timer.with_wheel(|wheel| {
1262            for handle in handles.borrow().iter() {
1263                wheel.relink(handle.hnd.get(), 1);
1264            }
1265        });
1266        make_due(&timer);
1267        let mut driver = timer_driver(&timer);
1268        assert!(
1269            Pin::new(&mut driver)
1270                .poll(&mut Context::from_waker(Waker::noop()))
1271                .is_pending()
1272        );
1273        assert_eq!(calls.get(), 1);
1274        assert_eq!(
1275            handles.borrow().iter().filter(|h| !h.is_elapsed()).count(),
1276            1
1277        );
1278        timer.elapsed_time.set(Some(
1279            Instant::now().checked_sub(Duration::from_secs(20)).unwrap(),
1280        ));
1281        for _ in 0..2 {
1282            assert!(
1283                Pin::new(&mut driver)
1284                    .poll(&mut Context::from_waker(Waker::noop()))
1285                    .is_pending()
1286            );
1287            assert_eq!(calls.get(), 2);
1288        }
1289    }
1290
1291    #[test]
1292    fn test_callback_capture_drop_schedules_timers() {
1293        for active in [false, true] {
1294            let timer = timer_state();
1295            let released = Rc::new(Cell::new(false));
1296            let finished = Rc::new(Cell::new(false));
1297            let reset_calls = Rc::new(Cell::new(0));
1298            let new_calls = Rc::new(Cell::new(0));
1299            let count = reset_calls.clone();
1300            let reset = Rc::new(CallbackTimer::new(Millis(20_000), move || {
1301                count.set(count.get() + 1);
1302            }));
1303            let cancelled = Rc::new(CallbackTimer::new(Millis(20_000), || {
1304                panic!("cancelled callback");
1305            }));
1306            let replacement = Rc::new(RefCell::new(None::<CallbackTimer>));
1307            let capture = {
1308                let reset = reset.clone();
1309                let cancelled = cancelled.clone();
1310                let replacement = replacement.clone();
1311                let new_calls = new_calls.clone();
1312                let released = released.clone();
1313                let finished = finished.clone();
1314                OnDropFn::new(move || {
1315                    assert!(!active || finished.get());
1316                    let ordinary = TimerHandle::new(10_000);
1317                    ordinary.reset(0);
1318                    drop(ordinary);
1319                    cancelled.cancel();
1320                    reset.reset(Millis(10_000));
1321                    *replacement.borrow_mut() =
1322                        Some(CallbackTimer::new(Millis(10_000), move || {
1323                            new_calls.set(new_calls.get() + 1);
1324                        }));
1325                    released.set(true);
1326                })
1327            };
1328            let handle = Rc::new(RefCell::new(None::<CallbackTimer>));
1329            let weak = Rc::downgrade(&handle);
1330            let was_released = released.clone();
1331            *handle.borrow_mut() = Some(CallbackTimer::new(Millis(1), move || {
1332                let _capture = &capture;
1333                assert!(active, "dropped queued callback must not run");
1334                drop(weak.upgrade().unwrap().borrow_mut().take());
1335                assert!(!was_released.get());
1336                finished.set(true);
1337            }));
1338            let old_slot = handle.borrow().as_ref().unwrap().hnd;
1339            if !active {
1340                timer.with_wheel(|wheel| {
1341                    wheel.relink(old_slot.get(), 1);
1342                    wheel.execute_expired_timers(1);
1343                });
1344                drop(handle.borrow_mut().take());
1345                assert!(released.get());
1346            }
1347            make_due(&timer);
1348            let mut driver = timer_driver(&timer);
1349            assert!(
1350                Pin::new(&mut driver)
1351                    .poll(&mut Context::from_waker(Waker::noop()))
1352                    .is_pending()
1353            );
1354            assert!(released.get());
1355            assert!(handle.borrow().is_none());
1356            assert!(cancelled.is_elapsed());
1357            assert!(!reset.is_elapsed());
1358            assert_eq!(replacement.borrow().as_ref().unwrap().hnd, old_slot);
1359            assert!(!replacement.borrow().as_ref().unwrap().is_elapsed());
1360            assert_eq!((reset_calls.get(), new_calls.get()), (0, 0));
1361
1362            timer.elapsed_time.set(Some(
1363                Instant::now().checked_sub(Duration::from_secs(20)).unwrap(),
1364            ));
1365            for _ in 0..2 {
1366                assert!(
1367                    Pin::new(&mut driver)
1368                        .poll(&mut Context::from_waker(Waker::noop()))
1369                        .is_pending()
1370                );
1371                assert_eq!((reset_calls.get(), new_calls.get()), (1, 1));
1372            }
1373        }
1374    }
1375
1376    #[test]
1377    fn test_callback_capture_drop_resets_runtime() {
1378        let timer = timer_state();
1379        let new_calls = Rc::new(Cell::new(0));
1380        let replacement = Rc::new(RefCell::new(None::<CallbackTimer>));
1381        let capture = {
1382            let timer = timer.clone();
1383            let new_calls = new_calls.clone();
1384            let replacement = replacement.clone();
1385            OnDropFn::new(move || {
1386                timer.reset();
1387                timer.insert_flags(Flags::DRIVER_STARTED);
1388                let callback = CallbackTimer::new(Millis(1), move || {
1389                    new_calls.set(new_calls.get() + 1);
1390                });
1391                timer.with_wheel(|wheel| {
1392                    wheel.relink(callback.hnd.get(), 1);
1393                    wheel.execute_expired_timers(1);
1394                });
1395                *replacement.borrow_mut() = Some(callback);
1396            })
1397        };
1398        let handle = Rc::new(RefCell::new(None::<CallbackTimer>));
1399        let weak = Rc::downgrade(&handle);
1400        *handle.borrow_mut() = Some(CallbackTimer::new(Millis(1), move || {
1401            let _capture = &capture;
1402            drop(weak.upgrade().unwrap().borrow_mut().take());
1403        }));
1404        make_due(&timer);
1405        let mut old_driver = timer_driver(&timer);
1406        assert!(
1407            Pin::new(&mut old_driver)
1408                .poll(&mut Context::from_waker(Waker::noop()))
1409                .is_ready()
1410        );
1411        assert!(handle.borrow().is_none());
1412        assert!(replacement.borrow().as_ref().unwrap().is_elapsed());
1413        assert_eq!(new_calls.get(), 0);
1414        drop(old_driver);
1415
1416        make_due(&timer);
1417        let mut driver = timer_driver(&timer);
1418        for _ in 0..2 {
1419            assert!(
1420                Pin::new(&mut driver)
1421                    .poll(&mut Context::from_waker(Waker::noop()))
1422                    .is_pending()
1423            );
1424            assert_eq!(new_calls.get(), 1);
1425        }
1426    }
1427
1428    #[test]
1429    fn test_callback_refreshes_time() {
1430        let timer = timer_state();
1431        let calls = Rc::new(Cell::new(0));
1432        let handles = [1, 32].map(|millis| {
1433            let calls = calls.clone();
1434            CallbackTimer::new(Millis(millis), move || {
1435                let previous = calls.replace(calls.get() + 1);
1436                if previous == 0 {
1437                    std::thread::sleep(Duration::from_millis(64));
1438                }
1439            })
1440        });
1441        timer.with_wheel(|wheel| {
1442            wheel.relink(handles[0].hnd.get(), 1);
1443            wheel.relink(handles[1].hnd.get(), 3);
1444        });
1445        timer.elapsed_time.set(Some(
1446            Instant::now()
1447                .checked_sub(Duration::from_millis(32))
1448                .unwrap(),
1449        ));
1450        let mut driver = timer_driver(&timer);
1451        assert!(
1452            Pin::new(&mut driver)
1453                .poll(&mut Context::from_waker(Waker::noop()))
1454                .is_pending()
1455        );
1456        assert_eq!(calls.get(), 2);
1457        assert!(handles.iter().all(CallbackTimer::is_elapsed));
1458    }
1459
1460    #[test]
1461    fn test_callback_panic_after_rearm_cleanup() {
1462        let timer = timer_state();
1463        let callback = Rc::new_cyclic(|weak: &std::rc::Weak<CallbackTimer>| {
1464            let weak = weak.clone();
1465            CallbackTimer::new(Millis(1), move || {
1466                let callback = weak.upgrade().unwrap();
1467                callback.reset(Millis(10_000));
1468                panic!("callback");
1469            })
1470        });
1471        let later = CallbackTimer::new(Millis(10_000), || panic!("not due"));
1472        let ordinary = TimerHandle::new(10_000);
1473        make_due(&timer);
1474        let mut driver = timer_driver(&timer);
1475        assert!(
1476            catch_unwind(AssertUnwindSafe(|| {
1477                let _ = Pin::new(&mut driver).poll(&mut Context::from_waker(Waker::noop()));
1478            }))
1479            .is_err()
1480        );
1481        assert!(!callback.is_elapsed());
1482        drop(driver);
1483        assert!(callback.is_elapsed());
1484        assert!(!callback.state.pending.get());
1485        assert!(later.is_elapsed());
1486        assert!(ordinary.is_elapsed());
1487        assert!(!later.state.pending.get());
1488        timer.with_wheel(|wheel| {
1489            assert!(wheel.buckets.iter().all(Slab::is_empty));
1490            assert_eq!(wheel.occupied, [0; LVL_DEPTH as usize]);
1491            assert!(wheel.callbacks.as_ref().unwrap().ready.is_empty());
1492        });
1493    }
1494
1495    #[test]
1496    fn test_callback_runtime_reset_during_delivery() {
1497        let timer = timer_state();
1498        let calls = Rc::new(Cell::new(0));
1499        let new_calls = Rc::new(Cell::new(0));
1500        let replacement = Rc::new(RefCell::new(None::<CallbackTimer>));
1501        let handles = [0, 1].map(|_| {
1502            let timer = timer.clone();
1503            let calls = calls.clone();
1504            let new_calls = new_calls.clone();
1505            let replacement = replacement.clone();
1506            CallbackTimer::new(Millis(1), move || {
1507                calls.set(calls.get() + 1);
1508                timer.reset();
1509                timer.insert_flags(Flags::DRIVER_STARTED);
1510                let new_calls = new_calls.clone();
1511                *replacement.borrow_mut() = Some(CallbackTimer::new(Millis(1), move || {
1512                    new_calls.set(new_calls.get() + 1);
1513                }));
1514            })
1515        });
1516        timer.with_wheel(|wheel| {
1517            for handle in &handles {
1518                wheel.relink(handle.hnd.get(), 1);
1519            }
1520        });
1521        make_due(&timer);
1522        let mut old_driver = timer_driver(&timer);
1523        assert!(
1524            Pin::new(&mut old_driver)
1525                .poll(&mut Context::from_waker(Waker::noop()))
1526                .is_ready()
1527        );
1528        assert_eq!(calls.get(), 1);
1529        assert!(handles.iter().all(CallbackTimer::is_elapsed));
1530        drop(old_driver);
1531        assert!(!replacement.borrow().as_ref().unwrap().is_elapsed());
1532        make_due(&timer);
1533        let mut driver = timer_driver(&timer);
1534        assert!(
1535            Pin::new(&mut driver)
1536                .poll(&mut Context::from_waker(Waker::noop()))
1537                .is_pending()
1538        );
1539        assert_eq!(new_calls.get(), 1);
1540    }
1541
1542    #[test]
1543    fn test_callback_mixed_bucket_waker_panic() {
1544        for panic_position in 0..3 {
1545            let timer = timer_state();
1546            let calls = Rc::new(Cell::new(0));
1547            let callbacks = [0, 1].map(|_| {
1548                let calls = calls.clone();
1549                CallbackTimer::new(Millis(10_000), move || calls.set(calls.get() + 1))
1550            });
1551            let ordinary = TimerHandle::new(10_000);
1552            let task = Arc::new(InPlaceWaker {
1553                panic_on_wake: true,
1554                ..InPlaceWaker::default()
1555            });
1556            let waker = Waker::from(task.clone());
1557            assert!(
1558                ordinary
1559                    .poll_elapsed(&mut Context::from_waker(&waker))
1560                    .is_pending()
1561            );
1562            timer.with_wheel(|wheel| {
1563                // Control slab drain positions, not public callback delivery order.
1564                let mut entries = [
1565                    callbacks[0].hnd.get(),
1566                    ordinary.0.get(),
1567                    callbacks[1].hnd.get(),
1568                ];
1569                entries.swap(1, panic_position);
1570                for no in entries {
1571                    wheel.unlink(no);
1572                }
1573                wheel.buckets[3] = Slab::new();
1574                for no in entries {
1575                    wheel.link(no, 3);
1576                }
1577            });
1578            timer.next_expiry.set(3);
1579            make_due(&timer);
1580            let mut driver = timer_driver(&timer);
1581            assert!(
1582                catch_unwind(AssertUnwindSafe(|| {
1583                    let _ = Pin::new(&mut driver).poll(&mut Context::from_waker(Waker::noop()));
1584                }))
1585                .is_err()
1586            );
1587            assert_eq!(task.wakes.load(Ordering::Relaxed), 1);
1588            assert_eq!(calls.get(), 0);
1589            assert!(ordinary.is_elapsed());
1590            assert!(callbacks.iter().all(CallbackTimer::is_elapsed));
1591            timer.with_wheel(|wheel| {
1592                assert!(wheel.buckets.iter().all(Slab::is_empty));
1593                assert_eq!(wheel.occupied, [0; LVL_DEPTH as usize]);
1594                assert_eq!(
1595                    wheel.callbacks.as_ref().unwrap().ready.len(),
1596                    panic_position
1597                );
1598            });
1599            drop(driver);
1600            assert!(
1601                callbacks
1602                    .iter()
1603                    .all(|callback| !callback.state.pending.get())
1604            );
1605            timer.with_wheel(|wheel| {
1606                assert!(wheel.callbacks.as_ref().unwrap().ready.is_empty());
1607            });
1608
1609            timer.insert_flags(Flags::DRIVER_STARTED);
1610            callbacks[0].reset(Millis::ZERO);
1611            make_due(&timer);
1612            let mut driver = timer_driver(&timer);
1613            for _ in 0..2 {
1614                assert!(
1615                    Pin::new(&mut driver)
1616                        .poll(&mut Context::from_waker(Waker::noop()))
1617                        .is_pending()
1618                );
1619                assert_eq!(calls.get(), 1);
1620            }
1621        }
1622    }
1623
1624    #[test]
1625    fn test_callback_reuse_in_next_system() {
1626        std::thread::spawn(|| {
1627            let calls = Rc::new(Cell::new(0));
1628            let mut callback = None::<CallbackTimer>;
1629            for expected in 1..=2 {
1630                let calls = calls.clone();
1631                callback = Some(
1632                    ntex::rt::System::build()
1633                        .build(ntex::rt::DefaultRuntime)
1634                        .block_on(async move {
1635                            let callback = if let Some(callback) = callback {
1636                                assert!(callback.is_elapsed());
1637                                sleep(Millis(50)).await;
1638                                assert_eq!(calls.get(), expected - 1);
1639                                callback.reset(Millis::ZERO);
1640                                callback
1641                            } else {
1642                                let calls = calls.clone();
1643                                CallbackTimer::new(Millis::ZERO, move || {
1644                                    calls.set(calls.get() + 1);
1645                                })
1646                            };
1647                            sleep(Millis(50)).await;
1648                            assert_eq!(calls.get(), expected);
1649                            callback.reset(Millis(10_000));
1650                            callback
1651                        }),
1652                );
1653                assert!(callback.as_ref().unwrap().is_elapsed());
1654            }
1655        })
1656        .join()
1657        .unwrap();
1658    }
1659
1660    #[test]
1661    fn test_wheel_access_restored_on_unwind() {
1662        let timer = Timer::new();
1663        assert!(
1664            catch_unwind(AssertUnwindSafe(|| {
1665                timer.with_wheel(|wheel| {
1666                    wheel.timers.insert(entry());
1667                    panic!("wheel operation");
1668                });
1669            }))
1670            .is_err()
1671        );
1672        timer.with_wheel(|wheel| assert_eq!(wheel.timers.len(), 2));
1673    }
1674
1675    #[test]
1676    fn test_wake_in_place() {
1677        let timer = timer_state();
1678        let task = Arc::new(InPlaceWaker::default());
1679        let waker = Waker::from(task.clone());
1680        let mut cx = Context::from_waker(&waker);
1681        for reset in [false, true] {
1682            let handle = TimerHandle::new(10_000);
1683            assert!(handle.poll_elapsed(&mut cx).is_pending());
1684            if reset {
1685                handle.reset(0);
1686            } else {
1687                handle.elapse();
1688            }
1689            assert!(handle.is_elapsed());
1690        }
1691        let handles = [TimerHandle::new(1), TimerHandle::new(1)];
1692        for handle in &handles {
1693            assert!(handle.poll_elapsed(&mut cx).is_pending());
1694        }
1695        timer.elapsed_time.set(Some(
1696            Instant::now().checked_sub(Duration::from_secs(20)).unwrap(),
1697        ));
1698        let mut driver = timer_driver(&timer);
1699        assert!(
1700            Pin::new(&mut driver)
1701                .poll(&mut Context::from_waker(Waker::noop()))
1702                .is_pending()
1703        );
1704        assert!(handles.iter().all(TimerHandle::is_elapsed));
1705        assert_eq!(task.wakes.load(Ordering::Relaxed), 4);
1706        assert_eq!(Arc::strong_count(&task), 2);
1707    }
1708
1709    #[test]
1710    fn test_dispatch_uses_one_time_sample_for_wakers() {
1711        let timer = timer_state();
1712        let handles = [TimerHandle::new(1), TimerHandle::new(32)];
1713        timer.with_wheel(|wheel| wheel.relink(handles[1].0.get(), 3));
1714        let task = Arc::new(InPlaceWaker {
1715            delay: Duration::from_millis(64),
1716            ..InPlaceWaker::default()
1717        });
1718        let waker = Waker::from(task.clone());
1719        for handle in &handles {
1720            assert!(
1721                handle
1722                    .poll_elapsed(&mut Context::from_waker(&waker))
1723                    .is_pending()
1724            );
1725        }
1726        timer.elapsed_time.set(Some(
1727            Instant::now()
1728                .checked_sub(Duration::from_millis(32))
1729                .unwrap(),
1730        ));
1731        let mut driver = timer_driver(&timer);
1732        assert!(
1733            Pin::new(&mut driver)
1734                .poll(&mut Context::from_waker(Waker::noop()))
1735                .is_pending()
1736        );
1737        assert!(handles[0].is_elapsed());
1738        assert!(!handles[1].is_elapsed());
1739        assert_eq!(task.wakes.load(Ordering::Relaxed), 1);
1740        assert!(
1741            Pin::new(&mut driver)
1742                .poll(&mut Context::from_waker(Waker::noop()))
1743                .is_pending()
1744        );
1745        assert!(handles[1].is_elapsed());
1746        assert_eq!(task.wakes.load(Ordering::Relaxed), 2);
1747    }
1748
1749    #[test]
1750    fn test_dispatch_panic_cleans_expired_bucket() {
1751        let timer = timer_state();
1752        let handles = [TimerHandle::new(1), TimerHandle::new(1)];
1753        timer.with_wheel(|wheel| {
1754            let bucket = wheel.timers[handles[0].0.get()].bucket.unwrap();
1755            wheel.relink(handles[1].0.get(), usize::from(bucket));
1756        });
1757        let task = Arc::new(InPlaceWaker {
1758            panic_on_wake: true,
1759            ..InPlaceWaker::default()
1760        });
1761        let waker = Waker::from(task.clone());
1762        for handle in &handles {
1763            assert!(
1764                handle
1765                    .poll_elapsed(&mut Context::from_waker(&waker))
1766                    .is_pending()
1767            );
1768        }
1769        timer.elapsed_time.set(Some(
1770            Instant::now()
1771                .checked_sub(Duration::from_millis(64))
1772                .unwrap(),
1773        ));
1774        let mut driver = timer_driver(&timer);
1775        assert!(
1776            catch_unwind(AssertUnwindSafe(|| {
1777                let _ = Pin::new(&mut driver).poll(&mut Context::from_waker(Waker::noop()));
1778            }))
1779            .is_err()
1780        );
1781        assert_eq!(task.wakes.load(Ordering::Relaxed), 1);
1782        assert!(handles.iter().all(TimerHandle::is_elapsed));
1783        timer.with_wheel(|wheel| {
1784            assert!(wheel.buckets.iter().all(Slab::is_empty));
1785            assert_eq!(wheel.occupied, [0; LVL_DEPTH as usize]);
1786        });
1787        for handle in &handles {
1788            handle.reset(10_000);
1789            assert!(!handle.is_elapsed());
1790        }
1791        drop(driver);
1792        assert!(handles.iter().all(TimerHandle::is_elapsed));
1793        assert!(!timer.flags.get().contains(Flags::DRIVER_STARTED));
1794    }
1795
1796    /// A handle dropped by a thread-local destructor after the wheel is
1797    /// destroyed must not panic.
1798    #[test]
1799    fn test_drop_handle_after_wheel_destroyed() {
1800        use std::cell::RefCell;
1801
1802        thread_local! {
1803            static HOLDER: RefCell<Option<TimerHandle>> = const { RefCell::new(None) };
1804        }
1805
1806        let res = std::thread::spawn(|| {
1807            // register the holder destructor first, the wheel is destroyed
1808            // before it, destructors run in reverse registration order
1809            HOLDER.with(|h| h.borrow_mut().take());
1810            ntex::rt::System::build()
1811                .build(ntex::rt::DefaultRuntime)
1812                .block_on(async {
1813                    let hnd = TimerHandle::new(1000);
1814                    std::future::poll_fn(|cx| {
1815                        assert!(hnd.poll_elapsed(cx).is_pending());
1816                        Poll::Ready(())
1817                    })
1818                    .await;
1819                    HOLDER.with(|h| *h.borrow_mut() = Some(hnd));
1820                });
1821        })
1822        .join();
1823        assert!(res.is_ok());
1824    }
1825
1826    #[test]
1827    fn test_drop_callback_after_wheel_destroyed() {
1828        thread_local! {
1829            static HOLDER: RefCell<Option<CallbackTimer>> = const { RefCell::new(None) };
1830        }
1831
1832        let drops = Arc::new(AtomicUsize::new(0));
1833        let destroyed = Arc::new(AtomicBool::new(false));
1834        let count = drops.clone();
1835        let was_destroyed = destroyed.clone();
1836        std::thread::spawn(move || {
1837            // Register this destructor before the timer's thread-local storage.
1838            HOLDER.with(|holder| holder.borrow_mut().take());
1839            ntex::rt::System::build()
1840                .build(ntex::rt::DefaultRuntime)
1841                .block_on(async move {
1842                    let ordinary = TimerHandle::new(10_000);
1843                    let capture = OnDropFn::new(move || {
1844                        was_destroyed.store(TIMER.try_with(|_| ()).is_err(), Ordering::Relaxed);
1845                        drop(ordinary);
1846                        count.fetch_add(1, Ordering::Relaxed);
1847                    });
1848                    let callback = CallbackTimer::new(Millis(10_000), move || {
1849                        let _capture = &capture;
1850                        panic!("callback after shutdown");
1851                    });
1852                    HOLDER.with(|holder| *holder.borrow_mut() = Some(callback));
1853                });
1854        })
1855        .join()
1856        .unwrap();
1857        assert!(destroyed.load(Ordering::Relaxed));
1858        assert_eq!(drops.load(Ordering::Relaxed), 1);
1859    }
1860
1861    /// The drivers of a stopped system may never be dropped, the next system
1862    /// on the same thread starts its own drivers.
1863    #[test]
1864    fn test_timer_in_next_system() {
1865        let res = std::thread::spawn(|| {
1866            for _ in 0..3 {
1867                let start = Instant::now();
1868                ntex::rt::System::build()
1869                    .build(ntex::rt::DefaultRuntime)
1870                    .block_on(async {
1871                        sleep(Millis(10)).await;
1872                        let _ = now();
1873                        // pending timer of the stopped system
1874                        let _hnd = sleep(Millis(10_000));
1875                        crate::spawn(async { sleep(Millis(10_000)).await });
1876                    });
1877                assert!(start.elapsed() < Duration::from_secs(5));
1878            }
1879        });
1880        let (tx, rx) = std::sync::mpsc::channel();
1881        std::thread::spawn(move || tx.send(res.join().is_ok()));
1882        assert_eq!(rx.recv_timeout(Duration::from_secs(10)), Ok(true));
1883    }
1884
1885    /// A stale driver does not stop the drivers of a newer generation.
1886    #[test]
1887    fn test_stale_driver_drop() {
1888        let timer = Rc::new(Timer::new());
1889        timer.insert_flags(Flags::RUNNING | Flags::DRIVER_STARTED | Flags::LOWRES_DRIVER);
1890        timer.reset();
1891        assert_eq!(timer.flags.get(), Flags::empty());
1892
1893        timer.insert_flags(Flags::RUNNING | Flags::DRIVER_STARTED | Flags::LOWRES_DRIVER);
1894        drop(TimerDriver {
1895            timer: timer.clone(),
1896            generation: 0,
1897            sleep: Delay::new(Duration::ZERO),
1898            armed: None,
1899        });
1900        drop(LowresTimerDriver {
1901            timer: timer.clone(),
1902            generation: 0,
1903            sleep: Delay::new(Duration::ZERO),
1904        });
1905        assert_eq!(
1906            timer.flags.get(),
1907            Flags::RUNNING | Flags::DRIVER_STARTED | Flags::LOWRES_DRIVER
1908        );
1909    }
1910
1911    fn entry() -> TimerEntry {
1912        TimerEntry {
1913            bucket: None,
1914            bucket_entry: 0,
1915            callback: false,
1916            task: None,
1917        }
1918    }
1919
1920    /// Bucket expiry is never earlier than the requested delay, and at most
1921    /// one level granularity later.
1922    #[test]
1923    fn test_bucket_expiry_bounds() {
1924        let timer = Timer::new();
1925        for elapsed in [0, 1, 7, 8, 63, 64, 511, 12_345, 1 << 30] {
1926            timer.elapsed.set(elapsed);
1927            let mut delta = 0;
1928            while delta < WHEEL_TIMEOUT_CUTOFF {
1929                let (idx, expiry) = timer.calc_wheel_index(elapsed + delta, delta);
1930                let lvl = (idx / LVL_SIZE as usize) as u64;
1931                assert!(expiry > elapsed + delta, "{elapsed} {delta} {expiry}");
1932                assert!(
1933                    expiry <= elapsed + delta + lvl_gran(lvl),
1934                    "{elapsed} {delta} {expiry}"
1935                );
1936                assert_eq!(expiry % lvl_gran(lvl), 0);
1937                assert_eq!(
1938                    ((expiry >> lvl_shift(lvl)) & LVL_MASK) as usize,
1939                    idx % LVL_SIZE as usize
1940                );
1941                delta = delta * 2 + 1;
1942            }
1943
1944            // clamped to the capacity of the wheel
1945            let (_, expiry) =
1946                timer.calc_wheel_index(elapsed + u64::from(u32::MAX), u64::from(u32::MAX));
1947            assert!(expiry <= elapsed + WHEEL_TIMEOUT_CUTOFF);
1948        }
1949    }
1950
1951    /// The next pending bucket is the earliest occupied one, and executing it
1952    /// wakes only its timers.
1953    #[test]
1954    fn test_next_pending_bucket() {
1955        let timer = Timer::new();
1956        timer.elapsed.set(1000);
1957
1958        timer.with_wheel(|w| {
1959            assert_eq!(timer.next_pending_bucket(w), None);
1960
1961            let mut expected = Vec::new();
1962            for delta in [5000, 30, 700, 100_000] {
1963                let (idx, expiry) = timer.calc_wheel_index(1000 + delta, delta);
1964                let no = w.timers.insert(entry());
1965                w.link(no, idx);
1966                expected.push((expiry, no));
1967            }
1968            expected.sort_unstable();
1969
1970            for (expiry, no) in expected {
1971                assert_eq!(timer.next_pending_bucket(w), Some(expiry));
1972                timer.elapsed.set(expiry);
1973                w.execute_expired_timers(expiry);
1974                assert!(w.timers[no].bucket.is_none());
1975            }
1976            assert_eq!(timer.next_pending_bucket(w), None);
1977            assert_eq!(w.occupied, [0; LVL_DEPTH as usize]);
1978        });
1979    }
1980
1981    #[test]
1982    fn test_unlink_relink() {
1983        let timer = Timer::new();
1984        timer.with_wheel(|w| {
1985            let a = w.timers.insert(entry());
1986            let b = w.timers.insert(entry());
1987            w.link(a, 3);
1988            w.link(b, 3);
1989            assert_eq!(w.occupied[0], 1 << 3);
1990
1991            assert!(w.unlink(a));
1992            assert!(!w.unlink(a));
1993            assert_eq!(w.occupied[0], 1 << 3);
1994
1995            w.relink(b, LVL_SIZE as usize + 5);
1996            assert_eq!(w.occupied[0], 0);
1997            assert_eq!(w.occupied[1], 1 << 5);
1998            assert_eq!(w.timers[b].bucket, Some(LVL_SIZE as u16 + 5));
1999
2000            assert!(w.unlink(b));
2001            assert_eq!(w.occupied, [0; LVL_DEPTH as usize]);
2002        });
2003    }
2004
2005    /// `reset(0)` elapses the timer and wakes the task waiting for it.
2006    #[ntex::test]
2007    async fn test_reset_zero_wakes_task() {
2008        let hnd = Rc::new(TimerHandle::new(10_000));
2009        let hnd2 = hnd.clone();
2010        crate::spawn(async move { hnd2.reset(0) });
2011
2012        // the sleep wakes the task if `reset(0)` does not
2013        let start = Instant::now();
2014        crate::future::select(
2015            std::future::poll_fn(|cx| hnd.poll_elapsed(cx)),
2016            sleep(Millis(500)),
2017        )
2018        .await;
2019        let elapsed = start.elapsed();
2020        assert!(elapsed < Duration::from_millis(100), "elapsed: {elapsed:?}");
2021    }
2022
2023    /// Dropping one driver does not reset the state of the other one.
2024    #[test]
2025    fn test_driver_drop_keeps_other_driver() {
2026        let timer = Rc::new(Timer::new());
2027        let no = timer.with_wheel(|w| {
2028            let no = w.timers.insert(entry());
2029            w.link(no, 3);
2030            no
2031        });
2032        timer.next_expiry.set(3);
2033        timer.lowres_stime.set(Some(SystemTime::now()));
2034        timer.insert_flags(
2035            Flags::RUNNING | Flags::DRIVER_STARTED | Flags::LOWRES_DRIVER | Flags::LOWRES_TIMER,
2036        );
2037
2038        drop(LowresTimerDriver {
2039            timer: timer.clone(),
2040            generation: 0,
2041            sleep: Delay::new(Duration::ZERO),
2042        });
2043        assert_eq!(timer.flags.get(), Flags::DRIVER_STARTED);
2044        assert!(timer.lowres_stime.get().is_none());
2045        // timers are still pending
2046        assert_eq!(timer.next_expiry.get(), 3);
2047        timer.with_wheel(|w| assert_eq!(w.timers[no].bucket, Some(3)));
2048
2049        timer.insert_flags(Flags::RUNNING | Flags::LOWRES_DRIVER);
2050        drop(TimerDriver {
2051            timer: timer.clone(),
2052            generation: 0,
2053            sleep: Delay::new(Duration::ZERO),
2054            armed: None,
2055        });
2056        assert_eq!(timer.flags.get(), Flags::LOWRES_DRIVER);
2057        assert_eq!(timer.next_expiry.get(), u64::MAX);
2058        timer.with_wheel(|w| {
2059            assert!(w.timers[no].bucket.is_none());
2060            assert_eq!(w.occupied, [0; LVL_DEPTH as usize]);
2061        });
2062    }
2063
2064    /// A short timer is measured from the current time, not from the cached
2065    /// time that went stale while the thread was blocked.
2066    #[ntex::test]
2067    async fn test_short_timer_after_blocking() {
2068        let _hnd = sleep(Millis(10_000));
2069        let _ = now();
2070
2071        // the lowres driver cannot run, the cached time goes stale
2072        std::thread::sleep(Duration::from_millis(100));
2073
2074        let start = Instant::now();
2075        sleep(Millis(50)).await;
2076        let elapsed = start.elapsed();
2077        assert!(elapsed >= Duration::from_millis(50), "elapsed: {elapsed:?}");
2078    }
2079
2080    /// `now()` does not go stale while the wheel is idle.
2081    #[ntex::test]
2082    async fn test_driver_cached_time_expires() {
2083        // the lowres timer of the cache populated at start fires first
2084        sleep(Millis(400)).await;
2085
2086        // the wheel is idle, the thread waits for a non-timer event
2087        let (tx, rx) = async_channel::bounded(1);
2088        std::thread::spawn(move || {
2089            std::thread::sleep(Duration::from_millis(600));
2090            let _ = tx.send_blocking(());
2091        });
2092        rx.recv().await.unwrap();
2093
2094        let stale = Instant::now().saturating_duration_since(now());
2095        assert!(stale < Duration::from_millis(300), "stale: {stale:?}");
2096    }
2097
2098    /// A late wakeup must not delay the timers that expire later.
2099    #[ntex::test]
2100    async fn test_late_wakeup_does_not_drift() {
2101        let start = Instant::now();
2102        let fut1 = sleep(Millis(50));
2103        let fut2 = sleep(Millis(600));
2104
2105        // block the thread, the driver wakes up ~450ms late for `fut1`.
2106        // `fut2` expires at ~620ms, with drift it would expire ~550ms after
2107        // the late wakeup, i.e. after ~1050ms. The bound leaves room for
2108        // scheduling latency on loaded machines.
2109        std::thread::sleep(Duration::from_millis(500));
2110        fut1.await;
2111        fut2.await;
2112
2113        let elapsed = start.elapsed();
2114        assert!(
2115            elapsed >= Duration::from_millis(600) && elapsed < Duration::from_millis(900),
2116            "elapsed: {elapsed:?}"
2117        );
2118    }
2119
2120    #[ntex::test]
2121    #[allow(unused_variables, clippy::used_underscore_binding)]
2122    async fn test_timer() {
2123        crate::spawn(async {
2124            let s = interval(Millis(25));
2125            loop {
2126                s.tick().await;
2127            }
2128        });
2129        let time = Instant::now();
2130        let fut1 = sleep(Millis(1000));
2131        let fut2 = sleep(Millis(200));
2132
2133        fut2.await;
2134        #[cfg(not(target_os = "macos"))]
2135        {
2136            let _elapsed = time.elapsed();
2137            assert!(
2138                _elapsed > Duration::from_millis(200) && _elapsed < Duration::from_millis(300),
2139                "elapsed: {_elapsed:?}"
2140            );
2141        }
2142
2143        fut1.await;
2144
2145        #[cfg(not(target_os = "macos"))]
2146        {
2147            let _elapsed = time.elapsed();
2148            assert!(
2149                _elapsed > Duration::from_secs(1) && _elapsed < Duration::from_millis(1200), // osx
2150                "elapsed: {_elapsed:?}",
2151            );
2152        }
2153
2154        let time = Instant::now();
2155        sleep(Millis(25)).await;
2156        #[cfg(not(target_os = "macos"))]
2157        {
2158            let _elapsed = time.elapsed();
2159            assert!(
2160                _elapsed > Duration::from_millis(20) && _elapsed < Duration::from_millis(50),
2161                "elapsed: {_elapsed:?}",
2162            );
2163        }
2164    }
2165}