1use 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
74const UNITS: u64 = 4;
76
77const LVL_CLK_SHIFT: u64 = 3;
79const LVL_CLK_DIV: u64 = 1 << LVL_CLK_SHIFT;
80const LVL_CLK_MASK: u64 = LVL_CLK_DIV - 1;
81
82const LVL_BITS: u64 = 6;
84const LVL_SIZE: u64 = 1 << LVL_BITS;
85const LVL_MASK: u64 = LVL_SIZE - 1;
86
87const LVL_DEPTH: u64 = 8;
89
90const WHEEL_SIZE: usize = (LVL_SIZE * LVL_DEPTH) as usize;
92
93const WHEEL_TIMEOUT_CUTOFF: u64 = lvl_start(LVL_DEPTH);
95const WHEEL_TIMEOUT_MAX: u64 = WHEEL_TIMEOUT_CUTOFF - lvl_gran(LVL_DEPTH - 1);
96
97const LOWRES_RESOLUTION: Duration = Duration::from_millis(150);
99
100const fn lvl_shift(lvl: u64) -> u64 {
102 lvl * LVL_CLK_SHIFT
103}
104
105const fn lvl_gran(lvl: u64) -> u64 {
107 1 << lvl_shift(lvl)
108}
109
110const 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#[inline]
133pub fn now() -> Instant {
134 ntex_rt::now()
135}
136
137#[inline]
141pub fn system_time() -> SystemTime {
142 TIMER.with(Timer::system_time)
143}
144
145#[derive(Debug)]
146pub struct TimerHandle(NonZeroUsize);
154
155impl TimerHandle {
156 pub fn new(millis: u64) -> Self {
158 TIMER.with(|t| t.add_timer(millis))
159 }
160
161 pub fn reset(&self, millis: u64) {
163 TIMER.with(|t| t.update_timer(self.0.get(), millis));
164 }
165
166 pub fn elapse(&self) {
168 TIMER.with(|t| t.remove_timer(self.0.get()));
169 }
170
171 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 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 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 const DRIVER_STARTED = 0b0000_0001;
212 const LOWRES_TIMER = 0b0000_1000;
214 const LOWRES_DRIVER = 0b0001_0000;
216 const RUNNING = 0b0010_0000;
218 }
219}
220
221thread_local! {
222 pub(super) static TIMER: Rc<Timer> = Rc::new(Timer::new());
223}
224
225pub(super) struct Timer {
227 elapsed: Cell<u64>,
229 elapsed_time: Cell<Option<Instant>>,
232 next_expiry: Cell<u64>,
234 flags: Cell<Flags>,
235 pub(super) generation: Cell<u64>,
237 driver: LocalWaker,
238 lowres_stime: Cell<Option<SystemTime>>,
239 lowres_driver: LocalWaker,
240 wheel: Cell<Option<Box<Wheel>>>,
242}
243
244pub(super) struct Wheel {
246 pub(super) timers: Slab<TimerEntry>,
249 buckets: Box<[Slab<usize>]>,
251 occupied: [u64; LVL_DEPTH as usize],
253 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 pub(super) bucket: Option<u16>,
272 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 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 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 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 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 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 TimerHandle(NonZeroUsize::new(no).unwrap())
409 }
410
411 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 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 pub(super) fn calc_bucket(self: &Rc<Self>, millis: u64) -> (usize, u64) {
436 self.insert_flags(Flags::RUNNING);
437
438 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 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 Self::calc_index(
456 self.elapsed.get().wrapping_add(WHEEL_TIMEOUT_MAX),
457 LVL_DEPTH - 1,
458 )
459 }
460
461 fn calc_index(expires: u64, lvl: u64) -> (usize, u64) {
463 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 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 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 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 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 if pos <= ((LVL_CLK_DIV - lvl_clk) & LVL_CLK_MASK) {
513 break;
514 }
515 }
516
517 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 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 fn stop_lowres(&self) {
537 self.remove_flags(Flags::LOWRES_DRIVER | Flags::LOWRES_TIMER);
538 self.lowres_stime.set(None);
539 }
540
541 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 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 fn bucket_bit(idx: usize) -> (usize, u64) {
588 (idx / LVL_SIZE as usize, 1 << (idx % LVL_SIZE as usize))
589 }
590
591 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 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 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 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 if (clk & LVL_CLK_MASK) != 0 {
655 break;
656 }
657 clk >>= LVL_CLK_SHIFT;
658 }
659 }
660}
661
662#[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 let _ = TIMER.try_with(|t| t.reset());
676 }
677}
678
679struct TimerDriver {
681 timer: Rc<Timer>,
682 generation: u64,
683 sleep: Delay,
684 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 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 this.armed = None;
743 continue;
744 }
745 }
746
747 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 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
795struct 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 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 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 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 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 #[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 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 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 #[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 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 #[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 #[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 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 #[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 #[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 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 #[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 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 #[ntex::test]
2067 async fn test_short_timer_after_blocking() {
2068 let _hnd = sleep(Millis(10_000));
2069 let _ = now();
2070
2071 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 #[ntex::test]
2082 async fn test_driver_cached_time_expires() {
2083 sleep(Millis(400)).await;
2085
2086 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 #[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 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), "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}