1use std::num::NonZeroUsize;
58use std::time::{Duration, Instant, SystemTime};
59use std::{cell::Cell, cmp, future::Future, pin::Pin, rc::Rc, task, task::Poll};
60
61use futures_timer::Delay;
62use slab::Slab;
63
64use crate::task::LocalWaker;
65
66const UNITS: u64 = 4;
68
69const LVL_CLK_SHIFT: u64 = 3;
71const LVL_CLK_DIV: u64 = 1 << LVL_CLK_SHIFT;
72const LVL_CLK_MASK: u64 = LVL_CLK_DIV - 1;
73
74const LVL_BITS: u64 = 6;
76const LVL_SIZE: u64 = 1 << LVL_BITS;
77const LVL_MASK: u64 = LVL_SIZE - 1;
78
79const LVL_DEPTH: u64 = 8;
81
82const WHEEL_SIZE: usize = (LVL_SIZE * LVL_DEPTH) as usize;
84
85const WHEEL_TIMEOUT_CUTOFF: u64 = lvl_start(LVL_DEPTH);
87const WHEEL_TIMEOUT_MAX: u64 = WHEEL_TIMEOUT_CUTOFF - lvl_gran(LVL_DEPTH - 1);
88
89const LOWRES_RESOLUTION: Duration = Duration::from_millis(150);
91
92const fn lvl_shift(lvl: u64) -> u64 {
94 lvl * LVL_CLK_SHIFT
95}
96
97const fn lvl_gran(lvl: u64) -> u64 {
99 1 << lvl_shift(lvl)
100}
101
102const fn lvl_start(lvl: u64) -> u64 {
105 (LVL_SIZE - 1) << ((lvl - 1) * LVL_CLK_SHIFT)
106}
107
108const fn to_units(millis: u64) -> u64 {
109 millis >> UNITS
110}
111
112const fn to_millis(units: u64) -> u64 {
113 units << UNITS
114}
115
116const fn as_millis(dur: Duration) -> u64 {
117 dur.as_secs() * 1_000 + (dur.subsec_millis() as u64)
118}
119
120#[inline]
124pub fn now() -> Instant {
125 TIMER.with(Timer::now)
126}
127
128#[inline]
132pub fn system_time() -> SystemTime {
133 TIMER.with(Timer::system_time)
134}
135
136#[derive(Debug)]
137pub struct TimerHandle(NonZeroUsize);
142
143impl TimerHandle {
144 pub fn new(millis: u64) -> Self {
146 TIMER.with(|t| t.add_timer(millis))
147 }
148
149 pub fn reset(&self, millis: u64) {
151 TIMER.with(|t| t.update_timer(self.0.get(), millis));
152 }
153
154 pub fn elapse(&self) {
156 TIMER.with(|t| t.remove_timer(self.0.get()));
157 }
158
159 pub fn is_elapsed(&self) -> bool {
161 TIMER.with(|t| t.with_wheel(|w| w.timers[self.0.get()].bucket.is_none()))
162 }
163
164 pub fn poll_elapsed(&self, cx: &mut task::Context<'_>) -> Poll<()> {
166 TIMER.with(|t| {
167 t.with_wheel(|w| {
168 let entry = &w.timers[self.0.get()];
169 if entry.bucket.is_none() {
170 Poll::Ready(())
171 } else {
172 entry.task.register(cx.waker());
173 Poll::Pending
174 }
175 })
176 })
177 }
178}
179
180impl Drop for TimerHandle {
181 fn drop(&mut self) {
182 let _ = TIMER.try_with(|t| {
185 t.with_wheel(|w| {
186 w.unlink(self.0.get());
187 w.timers.remove(self.0.get());
188 });
189 });
190 }
191}
192
193bitflags::bitflags! {
194 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
195 struct Flags: u8 {
196 const DRIVER_STARTED = 0b0000_0001;
198 const LOWRES_TIMER = 0b0000_1000;
200 const LOWRES_DRIVER = 0b0001_0000;
202 const RUNNING = 0b0010_0000;
204 }
205}
206
207thread_local! {
208 static TIMER: Rc<Timer> = Rc::new(Timer::new());
209}
210
211struct Timer {
213 elapsed: Cell<u64>,
215 elapsed_time: Cell<Option<Instant>>,
218 next_expiry: Cell<u64>,
220 flags: Cell<Flags>,
221 generation: Cell<u64>,
223 driver: LocalWaker,
224 lowres_time: Cell<Option<Instant>>,
225 lowres_stime: Cell<Option<SystemTime>>,
226 lowres_driver: LocalWaker,
227 wheel: Cell<Option<Box<Wheel>>>,
229}
230
231struct Wheel {
233 timers: Slab<TimerEntry>,
236 buckets: Box<[Slab<usize>]>,
238 occupied: [u64; LVL_DEPTH as usize],
240}
241
242#[derive(Debug)]
243struct TimerEntry {
244 bucket: Option<u16>,
246 bucket_entry: usize,
248 task: LocalWaker,
249}
250
251impl Timer {
252 fn new() -> Self {
253 let mut timers = Slab::default();
254 timers.insert(TimerEntry {
255 bucket: None,
256 bucket_entry: 0,
257 task: LocalWaker::new(),
258 });
259
260 Timer {
261 elapsed: Cell::new(0),
262 elapsed_time: Cell::new(None),
263 next_expiry: Cell::new(u64::MAX),
264 flags: Cell::new(Flags::empty()),
265 generation: Cell::new(0),
266 driver: LocalWaker::new(),
267 lowres_time: Cell::new(None),
268 lowres_stime: Cell::new(None),
269 lowres_driver: LocalWaker::new(),
270 wheel: Cell::new(Some(Box::new(Wheel {
271 timers,
272 buckets: (0..WHEEL_SIZE).map(|_| Slab::new()).collect(),
273 occupied: [0; LVL_DEPTH as usize],
274 }))),
275 }
276 }
277
278 fn with_wheel<F, R>(&self, f: F) -> R
279 where
280 F: FnOnce(&mut Wheel) -> R,
281 {
282 let mut wheel = self.wheel.take().unwrap();
283 let result = f(&mut wheel);
284 self.wheel.set(Some(wheel));
285 result
286 }
287
288 fn insert_flags(&self, flags: Flags) -> Flags {
289 let mut f = self.flags.get();
290 f.insert(flags);
291 self.flags.set(f);
292 f
293 }
294
295 fn now(self: &Rc<Self>) -> Instant {
298 if let Some(cur) = self.lowres_time.get() {
299 cur
300 } else {
301 let now = Instant::now();
302 if self.flags.get().contains(Flags::RUNNING) {
303 self.lowres_time.set(Some(now));
304 self.refresh_lowres();
305 }
306 now
307 }
308 }
309
310 fn system_time(self: &Rc<Self>) -> SystemTime {
311 if let Some(cur) = self.lowres_stime.get() {
312 cur
313 } else {
314 let now = SystemTime::now();
315 if self.flags.get().contains(Flags::RUNNING) {
316 self.lowres_stime.set(Some(now));
317 self.refresh_lowres();
318 }
319 now
320 }
321 }
322
323 fn refresh_lowres(self: &Rc<Self>) {
325 if self.flags.get().contains(Flags::LOWRES_DRIVER) {
326 self.lowres_driver.wake();
327 } else {
328 LowresTimerDriver::start(self);
329 }
330 }
331
332 fn elapsed_time(&self) -> Instant {
334 if let Some(elapsed_time) = self.elapsed_time.get() {
335 elapsed_time
336 } else {
337 let elapsed_time = Instant::now();
338 self.elapsed_time.set(Some(elapsed_time));
339 elapsed_time
340 }
341 }
342
343 fn add_timer(self: &Rc<Self>, millis: u64) -> TimerHandle {
344 let no = if millis == 0 {
345 self.with_wheel(|w| {
347 w.timers.insert(TimerEntry {
348 bucket: None,
349 bucket_entry: 0,
350 task: LocalWaker::new(),
351 })
352 })
353 } else {
354 let (idx, expiry) = self.calc_bucket(millis);
355 let no = self.with_wheel(|w| {
356 let no = w.timers.insert(TimerEntry {
357 bucket: None,
358 bucket_entry: 0,
359 task: LocalWaker::new(),
360 });
361 w.link(no, idx);
362 no
363 });
364 self.update_next_expiry(expiry);
365 no
366 };
367
368 TimerHandle(NonZeroUsize::new(no).unwrap())
370 }
371
372 fn update_timer(self: &Rc<Self>, hnd: usize, millis: u64) {
375 if millis == 0 {
376 self.remove_timer(hnd);
377 } else {
378 let (idx, expiry) = self.calc_bucket(millis);
379 self.with_wheel(|w| w.relink(hnd, idx));
380 self.update_next_expiry(expiry);
381 }
382 }
383
384 fn remove_timer(&self, hnd: usize) {
386 self.with_wheel(|w| {
387 if w.unlink(hnd) {
388 w.timers[hnd].task.wake();
389 }
390 });
391 }
392
393 fn calc_bucket(self: &Rc<Self>, millis: u64) -> (usize, u64) {
395 self.insert_flags(Flags::RUNNING);
396
397 let since = Instant::now().saturating_duration_since(self.elapsed_time());
401 let delta = to_units(as_millis(since) + millis);
402 self.calc_wheel_index(self.elapsed.get().wrapping_add(delta), delta)
403 }
404
405 fn calc_wheel_index(&self, expires: u64, delta: u64) -> (usize, u64) {
408 for lvl in 0..LVL_DEPTH {
409 if delta < lvl_start(lvl + 1) {
410 return Self::calc_index(expires, lvl);
411 }
412 }
413 Self::calc_index(
415 self.elapsed.get().wrapping_add(WHEEL_TIMEOUT_MAX),
416 LVL_DEPTH - 1,
417 )
418 }
419
420 fn calc_index(expires: u64, lvl: u64) -> (usize, u64) {
422 let expires = (expires + lvl_gran(lvl)) >> lvl_shift(lvl);
426 (
427 (lvl * LVL_SIZE + (expires & LVL_MASK)) as usize,
428 expires << lvl_shift(lvl),
429 )
430 }
431
432 fn update_next_expiry(self: &Rc<Self>, expiry: u64) {
434 if expiry < self.next_expiry.get() {
435 self.next_expiry.set(expiry);
436 if self.flags.get().contains(Flags::DRIVER_STARTED) {
437 self.driver.wake();
438 } else {
439 TimerDriver::start(self);
440 }
441 }
442 }
443
444 fn expiry_time(&self, expiry: u64) -> Instant {
446 self.elapsed_time()
447 + Duration::from_millis(to_millis(expiry.saturating_sub(self.elapsed.get())))
448 }
449
450 fn next_pending_bucket(&self, wheel: &Wheel) -> Option<u64> {
452 let mut clk = self.elapsed.get();
453 let mut next = u64::MAX;
454
455 for lvl in 0..LVL_DEPTH {
456 let lvl_clk = clk & LVL_CLK_MASK;
457 let occupied = wheel.occupied[lvl as usize];
458
459 if occupied != 0 {
460 let pos = u64::from(
462 occupied
463 .rotate_right((clk & LVL_MASK) as u32)
464 .trailing_zeros(),
465 );
466 next = cmp::min(next, (clk + pos) << lvl_shift(lvl));
467
468 if pos <= ((LVL_CLK_DIV - lvl_clk) & LVL_CLK_MASK) {
472 break;
473 }
474 }
475
476 clk >>= LVL_CLK_SHIFT;
480 clk += u64::from(lvl_clk != 0);
481 }
482
483 if next < u64::MAX { Some(next) } else { None }
484 }
485
486 fn remove_flags(&self, flags: Flags) {
489 let mut f = self.flags.get();
490 f.remove(flags | Flags::RUNNING);
491 self.flags.set(f);
492 }
493
494 fn stop_lowres(&self) {
496 self.remove_flags(Flags::LOWRES_DRIVER | Flags::LOWRES_TIMER);
497 self.lowres_time.set(None);
498 self.lowres_stime.set(None);
499 }
500
501 fn reset(&self) {
504 self.generation.set(self.generation.get().wrapping_add(1));
505 self.stop_wheel();
506 self.stop_lowres();
507 self.driver.take();
508 self.lowres_driver.take();
509 }
510
511 fn stop_wheel(&self) {
514 self.remove_flags(Flags::DRIVER_STARTED);
515
516 if let Some(mut wheel) = self.wheel.take() {
518 let Wheel {
519 timers,
520 buckets,
521 occupied,
522 } = &mut *wheel;
523 for bucket in buckets.iter_mut() {
524 for no in bucket.drain() {
525 timers[no].bucket = None;
526 }
527 }
528 *occupied = [0; LVL_DEPTH as usize];
529
530 self.next_expiry.set(u64::MAX);
531 self.elapsed.set(0);
532 self.elapsed_time.set(None);
533 self.wheel.set(Some(wheel));
534 }
535 }
536}
537
538impl Wheel {
539 fn bucket_bit(idx: usize) -> (usize, u64) {
541 (idx / LVL_SIZE as usize, 1 << (idx % LVL_SIZE as usize))
542 }
543
544 fn link(&mut self, hnd: usize, idx: usize) {
546 let entry = &mut self.timers[hnd];
547 entry.bucket = Some(idx as u16);
548 entry.bucket_entry = self.buckets[idx].insert(hnd);
549
550 let (lvl, bit) = Self::bucket_bit(idx);
551 self.occupied[lvl] |= bit;
552 }
553
554 fn unlink(&mut self, hnd: usize) -> bool {
558 let entry = &mut self.timers[hnd];
559 if let Some(idx) = entry.bucket.take() {
560 let idx = idx as usize;
561 let bucket = &mut self.buckets[idx];
562 bucket.remove(entry.bucket_entry);
563 if bucket.is_empty() {
564 let (lvl, bit) = Self::bucket_bit(idx);
565 self.occupied[lvl] &= !bit;
566 }
567 true
568 } else {
569 false
570 }
571 }
572
573 fn relink(&mut self, hnd: usize, idx: usize) {
575 if self.timers[hnd].bucket != Some(idx as u16) {
576 self.unlink(hnd);
577 self.link(hnd, idx);
578 }
579 }
580
581 fn execute_expired_timers(&mut self, mut clk: u64) {
583 for lvl in 0..LVL_DEPTH {
584 let idx = ((clk & LVL_MASK) + lvl * LVL_SIZE) as usize;
585 let bucket = &mut self.buckets[idx];
586 if !bucket.is_empty() {
587 let (lvl, bit) = Self::bucket_bit(idx);
588 self.occupied[lvl] &= !bit;
589 for no in bucket.drain() {
590 let entry = &mut self.timers[no];
591 entry.bucket = None;
592 entry.task.wake();
593 }
594 }
595
596 if (clk & LVL_CLK_MASK) != 0 {
599 break;
600 }
601 clk >>= LVL_CLK_SHIFT;
602 }
603 }
604}
605
606#[derive(Default)]
608struct TimerReset;
609
610impl TimerReset {
611 fn register() {
612 ntex_rt::with_item::<TimerReset, _, _>(|_| ());
613 }
614}
615
616impl Drop for TimerReset {
617 fn drop(&mut self) {
618 let _ = TIMER.try_with(|t| t.reset());
620 }
621}
622
623struct TimerDriver {
625 timer: Rc<Timer>,
626 generation: u64,
627 sleep: Delay,
628 armed: Option<Instant>,
630}
631
632impl TimerDriver {
633 fn start(timer: &Rc<Timer>) {
634 timer.insert_flags(Flags::DRIVER_STARTED);
635 TimerReset::register();
636
637 let deadline = timer.expiry_time(timer.next_expiry.get());
638 crate::spawn(TimerDriver {
639 timer: timer.clone(),
640 generation: timer.generation.get(),
641 sleep: Delay::new(deadline.saturating_duration_since(Instant::now())),
642 armed: Some(deadline),
643 });
644
645 timer.refresh_lowres();
647 }
648}
649
650impl Drop for TimerDriver {
651 fn drop(&mut self) {
652 if self.timer.generation.get() == self.generation {
653 self.timer.stop_wheel();
654 }
655 }
656}
657
658impl Future for TimerDriver {
659 type Output = ();
660
661 fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
662 let this = &mut *self;
663 let timer = &this.timer;
664 if timer.generation.get() != this.generation {
665 return Poll::Ready(());
666 }
667 timer.driver.register(cx.waker());
668
669 let now = Instant::now();
670 timer.lowres_time.set(Some(now));
671
672 loop {
673 let expiry = timer.next_expiry.get();
674 if expiry == u64::MAX {
675 return Poll::Pending;
677 }
678
679 let deadline = timer.expiry_time(expiry);
680 if deadline > now {
681 if this.armed != Some(deadline) {
682 this.armed = Some(deadline);
683 this.sleep.reset(deadline.saturating_duration_since(now));
684 }
685 if Pin::new(&mut this.sleep).poll(cx).is_pending() {
686 return Poll::Pending;
687 }
688 if deadline > now {
689 this.armed = None;
691 continue;
692 }
693 }
694
695 timer.elapsed.set(expiry);
698 timer.elapsed_time.set(Some(deadline));
699
700 let next = timer.with_wheel(|w| {
701 w.execute_expired_timers(expiry);
702 timer.next_pending_bucket(w)
703 });
704
705 if let Some(next) = next {
706 timer.next_expiry.set(next);
707 } else {
708 timer.next_expiry.set(u64::MAX);
709 timer.elapsed_time.set(None);
710 }
711 }
712 }
713}
714
715struct LowresTimerDriver {
717 timer: Rc<Timer>,
718 generation: u64,
719 sleep: Delay,
720}
721
722impl LowresTimerDriver {
723 fn start(timer: &Rc<Timer>) {
724 timer.insert_flags(Flags::LOWRES_DRIVER);
725 TimerReset::register();
726
727 crate::spawn(LowresTimerDriver {
728 timer: timer.clone(),
729 generation: timer.generation.get(),
730 sleep: Delay::new(LOWRES_RESOLUTION),
731 });
732 }
733}
734
735impl Drop for LowresTimerDriver {
736 fn drop(&mut self) {
737 if self.timer.generation.get() == self.generation {
738 self.timer.stop_lowres();
739 }
740 }
741}
742
743impl Future for LowresTimerDriver {
744 type Output = ();
745
746 fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
747 let this = &mut *self;
748 let timer = &this.timer;
749 if timer.generation.get() != this.generation {
750 return Poll::Ready(());
751 }
752 timer.lowres_driver.register(cx.waker());
753
754 let mut flags = timer.flags.get();
756 if !flags.contains(Flags::LOWRES_TIMER) {
757 flags.insert(Flags::LOWRES_TIMER);
758 timer.flags.set(flags);
759 this.sleep.reset(LOWRES_RESOLUTION);
760 }
761
762 if Pin::new(&mut this.sleep).poll(cx).is_ready() {
763 timer.lowres_time.set(None);
764 timer.lowres_stime.set(None);
765 flags.remove(Flags::LOWRES_TIMER);
766 timer.flags.set(flags);
767 }
768 Poll::Pending
769 }
770}
771
772#[cfg(test)]
773mod tests {
774 use super::*;
775 use crate::time::{Millis, interval, sleep};
776
777 #[test]
780 fn test_drop_handle_after_wheel_destroyed() {
781 use std::cell::RefCell;
782
783 thread_local! {
784 static HOLDER: RefCell<Option<TimerHandle>> = const { RefCell::new(None) };
785 }
786
787 let res = std::thread::spawn(|| {
788 HOLDER.with(|h| h.borrow_mut().take());
791 ntex::rt::System::build()
792 .build(ntex::rt::DefaultRuntime)
793 .block_on(async {
794 let hnd = TimerHandle::new(1000);
795 HOLDER.with(|h| *h.borrow_mut() = Some(hnd));
796 });
797 })
798 .join();
799 assert!(res.is_ok());
800 }
801
802 #[test]
805 fn test_timer_in_next_system() {
806 let res = std::thread::spawn(|| {
807 for _ in 0..3 {
808 let start = Instant::now();
809 ntex::rt::System::build()
810 .build(ntex::rt::DefaultRuntime)
811 .block_on(async {
812 sleep(Millis(10)).await;
813 let _ = now();
814 let _hnd = sleep(Millis(10_000));
816 crate::spawn(async { sleep(Millis(10_000)).await });
817 });
818 assert!(start.elapsed() < Duration::from_secs(5));
819 }
820 });
821 let (tx, rx) = std::sync::mpsc::channel();
822 std::thread::spawn(move || tx.send(res.join().is_ok()));
823 assert_eq!(rx.recv_timeout(Duration::from_secs(10)), Ok(true));
824 }
825
826 #[test]
828 fn test_stale_driver_drop() {
829 let timer = Rc::new(Timer::new());
830 timer.insert_flags(Flags::RUNNING | Flags::DRIVER_STARTED | Flags::LOWRES_DRIVER);
831 timer.reset();
832 assert_eq!(timer.flags.get(), Flags::empty());
833
834 timer.insert_flags(Flags::RUNNING | Flags::DRIVER_STARTED | Flags::LOWRES_DRIVER);
835 drop(TimerDriver {
836 timer: timer.clone(),
837 generation: 0,
838 sleep: Delay::new(Duration::ZERO),
839 armed: None,
840 });
841 drop(LowresTimerDriver {
842 timer: timer.clone(),
843 generation: 0,
844 sleep: Delay::new(Duration::ZERO),
845 });
846 assert_eq!(
847 timer.flags.get(),
848 Flags::RUNNING | Flags::DRIVER_STARTED | Flags::LOWRES_DRIVER
849 );
850 }
851
852 fn entry() -> TimerEntry {
853 TimerEntry {
854 bucket: None,
855 bucket_entry: 0,
856 task: LocalWaker::new(),
857 }
858 }
859
860 #[test]
863 fn test_bucket_expiry_bounds() {
864 let timer = Timer::new();
865 for elapsed in [0, 1, 7, 8, 63, 64, 511, 12_345, 1 << 30] {
866 timer.elapsed.set(elapsed);
867 let mut delta = 0;
868 while delta < WHEEL_TIMEOUT_CUTOFF {
869 let (idx, expiry) = timer.calc_wheel_index(elapsed + delta, delta);
870 let lvl = (idx / LVL_SIZE as usize) as u64;
871 assert!(expiry > elapsed + delta, "{elapsed} {delta} {expiry}");
872 assert!(
873 expiry <= elapsed + delta + lvl_gran(lvl),
874 "{elapsed} {delta} {expiry}"
875 );
876 assert_eq!(expiry % lvl_gran(lvl), 0);
877 assert_eq!(
878 ((expiry >> lvl_shift(lvl)) & LVL_MASK) as usize,
879 idx % LVL_SIZE as usize
880 );
881 delta = delta * 2 + 1;
882 }
883
884 let (_, expiry) =
886 timer.calc_wheel_index(elapsed + u64::from(u32::MAX), u64::from(u32::MAX));
887 assert!(expiry <= elapsed + WHEEL_TIMEOUT_CUTOFF);
888 }
889 }
890
891 #[test]
894 fn test_next_pending_bucket() {
895 let timer = Timer::new();
896 timer.elapsed.set(1000);
897
898 timer.with_wheel(|w| {
899 assert_eq!(timer.next_pending_bucket(w), None);
900
901 let mut expected = Vec::new();
902 for delta in [5000, 30, 700, 100_000] {
903 let (idx, expiry) = timer.calc_wheel_index(1000 + delta, delta);
904 let no = w.timers.insert(entry());
905 w.link(no, idx);
906 expected.push((expiry, no));
907 }
908 expected.sort_unstable();
909
910 for (expiry, no) in expected {
911 assert_eq!(timer.next_pending_bucket(w), Some(expiry));
912 timer.elapsed.set(expiry);
913 w.execute_expired_timers(expiry);
914 assert!(w.timers[no].bucket.is_none());
915 }
916 assert_eq!(timer.next_pending_bucket(w), None);
917 assert_eq!(w.occupied, [0; LVL_DEPTH as usize]);
918 });
919 }
920
921 #[test]
922 fn test_unlink_relink() {
923 let timer = Timer::new();
924 timer.with_wheel(|w| {
925 let a = w.timers.insert(entry());
926 let b = w.timers.insert(entry());
927 w.link(a, 3);
928 w.link(b, 3);
929 assert_eq!(w.occupied[0], 1 << 3);
930
931 assert!(w.unlink(a));
932 assert!(!w.unlink(a));
933 assert_eq!(w.occupied[0], 1 << 3);
934
935 w.relink(b, LVL_SIZE as usize + 5);
936 assert_eq!(w.occupied[0], 0);
937 assert_eq!(w.occupied[1], 1 << 5);
938 assert_eq!(w.timers[b].bucket, Some(LVL_SIZE as u16 + 5));
939
940 assert!(w.unlink(b));
941 assert_eq!(w.occupied, [0; LVL_DEPTH as usize]);
942 });
943 }
944
945 #[ntex::test]
947 async fn test_reset_zero_wakes_task() {
948 let hnd = Rc::new(TimerHandle::new(10_000));
949 let hnd2 = hnd.clone();
950 crate::spawn(async move { hnd2.reset(0) });
951
952 let start = Instant::now();
954 crate::future::select(
955 std::future::poll_fn(|cx| hnd.poll_elapsed(cx)),
956 sleep(Millis(500)),
957 )
958 .await;
959 let elapsed = start.elapsed();
960 assert!(elapsed < Duration::from_millis(100), "elapsed: {elapsed:?}");
961 }
962
963 #[test]
965 fn test_driver_drop_keeps_other_driver() {
966 let timer = Rc::new(Timer::new());
967 let no = timer.with_wheel(|w| {
968 let no = w.timers.insert(entry());
969 w.link(no, 3);
970 no
971 });
972 timer.next_expiry.set(3);
973 timer.lowres_time.set(Some(Instant::now()));
974 timer.insert_flags(
975 Flags::RUNNING | Flags::DRIVER_STARTED | Flags::LOWRES_DRIVER | Flags::LOWRES_TIMER,
976 );
977
978 drop(LowresTimerDriver {
979 timer: timer.clone(),
980 generation: 0,
981 sleep: Delay::new(Duration::ZERO),
982 });
983 assert_eq!(timer.flags.get(), Flags::DRIVER_STARTED);
984 assert!(timer.lowres_time.get().is_none());
985 assert_eq!(timer.next_expiry.get(), 3);
987 timer.with_wheel(|w| assert_eq!(w.timers[no].bucket, Some(3)));
988
989 timer.insert_flags(Flags::RUNNING | Flags::LOWRES_DRIVER);
990 drop(TimerDriver {
991 timer: timer.clone(),
992 generation: 0,
993 sleep: Delay::new(Duration::ZERO),
994 armed: None,
995 });
996 assert_eq!(timer.flags.get(), Flags::LOWRES_DRIVER);
997 assert_eq!(timer.next_expiry.get(), u64::MAX);
998 timer.with_wheel(|w| {
999 assert!(w.timers[no].bucket.is_none());
1000 assert_eq!(w.occupied, [0; LVL_DEPTH as usize]);
1001 });
1002 }
1003
1004 #[ntex::test]
1007 async fn test_short_timer_after_blocking() {
1008 let _hnd = sleep(Millis(10_000));
1009 let _ = now();
1010
1011 std::thread::sleep(Duration::from_millis(100));
1013
1014 let start = Instant::now();
1015 sleep(Millis(50)).await;
1016 let elapsed = start.elapsed();
1017 assert!(elapsed >= Duration::from_millis(50), "elapsed: {elapsed:?}");
1018 }
1019
1020 #[ntex::test]
1022 async fn test_late_wakeup_does_not_drift() {
1023 let start = Instant::now();
1024 let fut1 = sleep(Millis(50));
1025 let fut2 = sleep(Millis(600));
1026
1027 std::thread::sleep(Duration::from_millis(500));
1032 fut1.await;
1033 fut2.await;
1034
1035 let elapsed = start.elapsed();
1036 assert!(
1037 elapsed >= Duration::from_millis(600) && elapsed < Duration::from_millis(900),
1038 "elapsed: {elapsed:?}"
1039 );
1040 }
1041
1042 #[ntex::test]
1043 #[allow(unused_variables, clippy::used_underscore_binding)]
1044 async fn test_timer() {
1045 crate::spawn(async {
1046 let s = interval(Millis(25));
1047 loop {
1048 s.tick().await;
1049 }
1050 });
1051 let time = Instant::now();
1052 let fut1 = sleep(Millis(1000));
1053 let fut2 = sleep(Millis(200));
1054
1055 fut2.await;
1056 #[cfg(not(target_os = "macos"))]
1057 {
1058 let _elapsed = time.elapsed();
1059 assert!(
1060 _elapsed > Duration::from_millis(200) && _elapsed < Duration::from_millis(300),
1061 "elapsed: {_elapsed:?}"
1062 );
1063 }
1064
1065 fut1.await;
1066
1067 #[cfg(not(target_os = "macos"))]
1068 {
1069 let _elapsed = time.elapsed();
1070 assert!(
1071 _elapsed > Duration::from_secs(1) && _elapsed < Duration::from_millis(1200), "elapsed: {_elapsed:?}",
1073 );
1074 }
1075
1076 let time = Instant::now();
1077 sleep(Millis(25)).await;
1078 #[cfg(not(target_os = "macos"))]
1079 {
1080 let _elapsed = time.elapsed();
1081 assert!(
1082 _elapsed > Duration::from_millis(20) && _elapsed < Duration::from_millis(50),
1083 "elapsed: {_elapsed:?}",
1084 );
1085 }
1086 }
1087}