1#![allow(arithmetic_overflow)]
5use std::num::NonZeroUsize;
6use std::time::{Duration, Instant, SystemTime};
7use std::{cell::Cell, cmp::max, future::Future, mem, pin::Pin, rc::Rc, task, task::Poll};
8
9use futures_timer::Delay;
10use slab::Slab;
11
12use crate::task::LocalWaker;
13
14const LVL_CLK_SHIFT: u64 = 3;
16const LVL_CLK_DIV: u64 = 1 << LVL_CLK_SHIFT;
17const LVL_CLK_MASK: u64 = LVL_CLK_DIV - 1;
18
19const fn lvl_shift(n: u64) -> u64 {
20 n * LVL_CLK_SHIFT
21}
22
23const fn lvl_gran(n: u64) -> u64 {
24 1 << lvl_shift(n)
25}
26
27const UNITS: u64 = 4;
31const fn to_units(n: u64) -> u64 {
34 n >> UNITS
35}
36
37const fn to_millis(n: u64) -> u64 {
38 n << UNITS
39}
40
41const fn lvl_start(lvl: u64) -> u64 {
43 (LVL_SIZE - 1) << ((lvl - 1) * LVL_CLK_SHIFT)
44}
45
46const LVL_BITS: u64 = 6;
48const LVL_SIZE: u64 = 1 << LVL_BITS;
49const LVL_MASK: u64 = LVL_SIZE - 1;
50
51const LVL_DEPTH: u64 = 8;
53
54const fn lvl_offs(n: u64) -> u64 {
55 n * LVL_SIZE
56}
57
58const WHEEL_TIMEOUT_CUTOFF: u64 = lvl_start(LVL_DEPTH);
60const WHEEL_TIMEOUT_MAX: u64 = WHEEL_TIMEOUT_CUTOFF - (lvl_gran(LVL_DEPTH - 1));
61const WHEEL_SIZE: usize = (LVL_SIZE as usize) * (LVL_DEPTH as usize);
62
63const LOWRES_RESOLUTION: Duration = Duration::from_millis(5);
65
66const fn as_millis(dur: Duration) -> u64 {
67 dur.as_secs() * 1_000 + (dur.subsec_millis() as u64)
68}
69
70#[inline]
74pub fn now() -> Instant {
75 TIMER.with(|t| t.with_mod(|inner| t.now(inner)))
76}
77
78#[inline]
82pub fn system_time() -> SystemTime {
83 TIMER.with(|t| t.with_mod(|inner| t.system_time(inner)))
84}
85
86#[inline]
91pub fn query_system_time() -> SystemTime {
92 TIMER.with(|t| t.with_mod(|inner| t.system_time(inner)))
93}
94
95#[derive(Debug)]
96pub struct TimerHandle(NonZeroUsize);
101
102impl TimerHandle {
103 pub fn new(millis: u64) -> Self {
105 TIMER.with(|t| t.add_timer(millis))
106 }
107
108 pub fn reset(&self, millis: u64) {
110 TIMER.with(|t| t.update_timer(self.0.get(), millis));
111 }
112
113 pub fn elapse(&self) {
115 TIMER.with(|t| t.remove_timer(self.0.get()));
116 }
117
118 pub fn is_elapsed(&self) -> bool {
120 TIMER.with(|t| t.with_mod(|m| m.timers[self.0.get()].bucket.is_none()))
121 }
122
123 pub fn poll_elapsed(&self, cx: &mut task::Context<'_>) -> Poll<()> {
125 TIMER.with(|t| {
126 t.with_mod(|inner| {
127 let entry = &inner.timers[self.0.get()];
128 if entry.bucket.is_none() {
129 Poll::Ready(())
130 } else {
131 entry.task.register(cx.waker());
132 Poll::Pending
133 }
134 })
135 })
136 }
137}
138
139impl Drop for TimerHandle {
140 fn drop(&mut self) {
141 TIMER.with(|t| t.with_mod(|inner| inner.remove_timer_bucket(self.0.get(), true)));
142 }
143}
144
145bitflags::bitflags! {
146 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
147 pub struct Flags: u8 {
148 const DRIVER_STARTED = 0b0000_0001;
149 const DRIVER_RECALC = 0b0000_0010;
150 const LOWRES_TIMER = 0b0000_1000;
151 const LOWRES_DRIVER = 0b0001_0000;
152 const RUNNING = 0b0010_0000;
153 }
154}
155
156thread_local! {
157 static TIMER: Timer = Timer::new();
158}
159
160struct Timer(Rc<TimerInner>);
161
162struct TimerInner {
163 elapsed: Cell<u64>,
164 elapsed_time: Cell<Option<Instant>>,
165 next_expiry: Cell<u64>,
166 flags: Cell<Flags>,
167 driver: LocalWaker,
168 lowres_time: Cell<Option<Instant>>,
169 lowres_stime: Cell<Option<SystemTime>>,
170 lowres_driver: LocalWaker,
171 inner: Cell<Option<Box<TimerMod>>>,
172}
173
174struct TimerMod {
175 timers: Slab<TimerEntry>,
176 driver_sleep: Delay,
177 buckets: Vec<Bucket>,
178 occupied: [u64; WHEEL_SIZE],
180 lowres_driver_sleep: Delay,
181}
182
183impl Timer {
184 fn new() -> Self {
185 let mut timers = Slab::default();
186 timers.insert(TimerEntry {
188 bucket: None,
189 bucket_entry: 0,
190 task: LocalWaker::new(),
191 });
192
193 Timer(Rc::new(TimerInner {
194 elapsed: Cell::new(0),
195 elapsed_time: Cell::new(None),
196 next_expiry: Cell::new(u64::MAX),
197 flags: Cell::new(Flags::empty()),
198 driver: LocalWaker::new(),
199 lowres_time: Cell::new(None),
200 lowres_stime: Cell::new(None),
201 lowres_driver: LocalWaker::new(),
202 inner: Cell::new(Some(Box::new(TimerMod {
203 timers,
204 buckets: Self::create_buckets(),
205 driver_sleep: Delay::new(Duration::ZERO),
206 occupied: [0; WHEEL_SIZE],
207 lowres_driver_sleep: Delay::new(Duration::ZERO),
208 }))),
209 }))
210 }
211
212 fn with_mod<F, R>(&self, f: F) -> R
213 where
214 F: FnOnce(&mut TimerMod) -> R,
215 {
216 let mut m = self.0.inner.take().unwrap();
217 let result = f(&mut m);
218 self.0.inner.set(Some(m));
219 result
220 }
221
222 fn create_buckets() -> Vec<Bucket> {
223 let mut buckets = Vec::with_capacity(WHEEL_SIZE);
224 for idx in 0..WHEEL_SIZE {
225 let lvl = idx / (LVL_SIZE as usize);
226 let offs = idx % (LVL_SIZE as usize);
227 buckets.push(Bucket::new(lvl, offs));
228 }
229 buckets
230 }
231
232 fn now(&self, inner: &mut TimerMod) -> Instant {
233 if let Some(cur) = self.0.lowres_time.get() {
234 cur
235 } else {
236 let now = Instant::now();
237
238 let flags = self.0.flags.get();
239 if flags.contains(Flags::RUNNING) {
240 self.0.lowres_time.set(Some(now));
241
242 if flags.contains(Flags::LOWRES_DRIVER) {
243 self.0.lowres_driver.wake();
244 } else {
245 LowresTimerDriver::start(self.0.clone(), inner);
246 }
247 }
248 now
249 }
250 }
251
252 fn system_time(&self, inner: &mut TimerMod) -> SystemTime {
253 if let Some(cur) = self.0.lowres_stime.get() {
254 cur
255 } else {
256 let now = SystemTime::now();
257 let flags = self.0.flags.get();
258
259 if flags.contains(Flags::RUNNING) {
260 self.0.lowres_stime.set(Some(now));
261
262 if flags.contains(Flags::LOWRES_DRIVER) {
263 self.0.lowres_driver.wake();
264 } else {
265 LowresTimerDriver::start(self.0.clone(), inner);
266 }
267 }
268 now
269 }
270 }
271
272 fn add_timer(&self, millis: u64) -> TimerHandle {
274 self.with_mod(|inner| {
275 if millis == 0 {
276 let entry = inner.timers.vacant_entry();
277 let no = entry.key();
278
279 entry.insert(TimerEntry {
280 bucket_entry: 0,
281 bucket: None,
282 task: LocalWaker::new(),
283 });
284 return TimerHandle(unsafe { NonZeroUsize::new_unchecked(no) });
286 }
287
288 let mut flags = self.0.flags.get();
289 flags.insert(Flags::RUNNING);
290 self.0.flags.set(flags);
291
292 let now = self.now(inner);
293 let elapsed_time = self.0.elapsed_time();
294 let delta = if now >= elapsed_time {
295 to_units(as_millis(now - elapsed_time) + millis)
296 } else {
297 to_units(millis)
298 };
299
300 let (no, bucket_expiry) = {
301 let (idx, bucket_expiry) = self
303 .0
304 .calc_wheel_index(self.0.elapsed.get().wrapping_add(delta), delta);
305
306 let no = inner.add_entry(idx);
307 (no, bucket_expiry)
308 };
309
310 if bucket_expiry < self.0.next_expiry.get() {
312 self.0.next_expiry.set(bucket_expiry);
313 if flags.contains(Flags::DRIVER_STARTED) {
314 flags.insert(Flags::DRIVER_RECALC);
315 self.0.flags.set(flags);
316 self.0.driver.wake();
317 } else {
318 TimerDriver::start(self.0.clone(), inner);
319 }
320 }
321
322 TimerHandle(unsafe { NonZeroUsize::new_unchecked(no) })
324 })
325 }
326
327 fn remove_timer(&self, hnd: usize) {
329 self.with_mod(|inner| {
330 inner.remove_timer_bucket(hnd, false);
331 inner.timers[hnd].complete();
332 });
333 }
334
335 fn update_timer(&self, hnd: usize, millis: u64) {
337 self.with_mod(|inner| {
338 if millis == 0 {
339 inner.remove_timer_bucket(hnd, false);
340 inner.timers[hnd].bucket = None;
341 return;
342 }
343
344 let now = self.now(inner);
345 let elapsed_time = self.0.elapsed_time();
346 let delta = if now >= elapsed_time {
347 max(to_units(as_millis(now - elapsed_time) + millis), 1)
348 } else {
349 max(to_units(millis), 1)
350 };
351
352 let bucket_expiry = {
353 let (idx, bucket_expiry) = self
355 .0
356 .calc_wheel_index(self.0.elapsed.get().wrapping_add(delta), delta);
357
358 inner.update_entry(hnd, idx);
359
360 bucket_expiry
361 };
362
363 if bucket_expiry < self.0.next_expiry.get() {
365 self.0.next_expiry.set(bucket_expiry);
366 let mut flags = self.0.flags.get();
367 if flags.contains(Flags::DRIVER_STARTED) {
368 flags.insert(Flags::DRIVER_RECALC);
369 self.0.flags.set(flags);
370 self.0.driver.wake();
371 } else {
372 TimerDriver::start(self.0.clone(), inner);
373 }
374 }
375 });
376 }
377}
378
379impl TimerMod {
380 fn execute_expired_timers(&mut self, mut clk: u64) {
381 for lvl in 0..LVL_DEPTH {
382 let idx = (clk & LVL_MASK) + lvl * LVL_SIZE;
383 let b = &mut self.buckets[idx as usize];
384 if !b.entries.is_empty() {
385 self.occupied[b.lvl as usize] &= b.bit_n;
386 for no in b.entries.drain() {
387 if let Some(timer) = self.timers.get_mut(no) {
388 timer.complete();
389 }
390 }
391 }
392
393 if (clk & LVL_CLK_MASK) != 0 {
395 break;
396 }
397 clk >>= LVL_CLK_SHIFT;
399 }
400 }
401
402 fn remove_timer_bucket(&mut self, handle: usize, remove_handle: bool) {
403 let entry = &mut self.timers[handle];
404 if let Some(bucket) = entry.bucket {
405 let b = &mut self.buckets[bucket as usize];
406 b.entries.remove(entry.bucket_entry);
407 if b.entries.is_empty() {
408 self.occupied[b.lvl as usize] &= b.bit_n;
409 }
410 }
411
412 if remove_handle {
413 self.timers.remove(handle);
414 }
415 }
416
417 fn add_entry(&mut self, idx: usize) -> usize {
418 let entry = self.timers.vacant_entry();
419 let no = entry.key();
420 let bucket = &mut self.buckets[idx];
421 let bucket_entry = bucket.add_entry(no);
422
423 entry.insert(TimerEntry {
424 bucket_entry,
425 bucket: Some(idx as u16),
426 task: LocalWaker::new(),
427 });
428 self.occupied[bucket.lvl as usize] |= bucket.bit;
429
430 no
431 }
432
433 fn update_entry(&mut self, hnd: usize, idx: usize) {
434 let entry = &mut self.timers[hnd];
435
436 if let Some(bucket) = entry.bucket {
438 if idx == bucket as usize {
440 return;
441 }
442
443 let b = &mut self.buckets[bucket as usize];
445 b.entries.remove(entry.bucket_entry);
446 if b.entries.is_empty() {
447 self.occupied[b.lvl as usize] &= b.bit_n;
448 }
449 }
450
451 let bucket = &mut self.buckets[idx];
453 entry.bucket = Some(idx as u16);
454 entry.bucket_entry = bucket.add_entry(hnd);
455
456 self.occupied[bucket.lvl as usize] |= bucket.bit;
457 }
458}
459
460impl TimerInner {
461 fn with_mod<F, R>(&self, f: F) -> R
462 where
463 F: FnOnce(&mut TimerMod) -> R,
464 {
465 let mut m = self.inner.take().unwrap();
466 let result = f(&mut m);
467 self.inner.set(Some(m));
468 result
469 }
470
471 fn calc_wheel_index(&self, expires: u64, delta: u64) -> (usize, u64) {
472 if delta < lvl_start(1) {
473 Self::calc_index(expires, 0)
474 } else if delta < lvl_start(2) {
475 Self::calc_index(expires, 1)
476 } else if delta < lvl_start(3) {
477 Self::calc_index(expires, 2)
478 } else if delta < lvl_start(4) {
479 Self::calc_index(expires, 3)
480 } else if delta < lvl_start(5) {
481 Self::calc_index(expires, 4)
482 } else if delta < lvl_start(6) {
483 Self::calc_index(expires, 5)
484 } else if delta < lvl_start(7) {
485 Self::calc_index(expires, 6)
486 } else if delta < lvl_start(8) {
487 Self::calc_index(expires, 7)
488 } else {
489 if delta >= WHEEL_TIMEOUT_CUTOFF {
492 Self::calc_index(
493 self.elapsed.get().wrapping_add(WHEEL_TIMEOUT_MAX),
494 LVL_DEPTH - 1,
495 )
496 } else {
497 Self::calc_index(expires, LVL_DEPTH - 1)
498 }
499 }
500 }
501
502 fn calc_index(expires: u64, lvl: u64) -> (usize, u64) {
504 let expires = (expires + lvl_gran(lvl)) >> lvl_shift(lvl);
512 (
513 (lvl_offs(lvl) + (expires & LVL_MASK)) as usize,
514 expires << lvl_shift(lvl),
515 )
516 }
517
518 fn elapsed_time(&self) -> Instant {
519 if let Some(elapsed_time) = self.elapsed_time.get() {
520 elapsed_time
521 } else {
522 let elapsed_time = Instant::now();
523 self.elapsed_time.set(Some(elapsed_time));
524 elapsed_time
525 }
526 }
527
528 fn execute_expired_timers(&self, inner: &mut TimerMod) {
529 inner.execute_expired_timers(self.next_expiry.get());
530 }
531
532 fn next_pending_bucket(&self, inner: &mut TimerMod) -> Option<u64> {
534 let mut clk = self.elapsed.get();
535 let mut next = u64::MAX;
536
537 for lvl in 0..LVL_DEPTH {
538 let lvl_clk = clk & LVL_CLK_MASK;
539 let occupied = inner.occupied[lvl as usize];
540 let pos = if occupied == 0 {
541 -1
542 } else {
543 let zeros = occupied
544 .rotate_right((clk & LVL_MASK) as u32)
545 .trailing_zeros() as usize;
546 zeros as isize
547 };
548
549 if pos >= 0 {
550 let tmp = (clk + pos as u64) << lvl_shift(lvl);
551 if tmp < next {
552 next = tmp;
553 }
554
555 if (pos as u64) <= ((LVL_CLK_DIV - lvl_clk) & LVL_CLK_MASK) {
558 break;
559 }
560 }
561
562 clk >>= LVL_CLK_SHIFT;
563 clk += u64::from(lvl_clk != 0);
564 }
565
566 if next < u64::MAX { Some(next) } else { None }
567 }
568
569 fn next_expiry_ms(&self) -> u64 {
571 to_millis(self.next_expiry.get().saturating_sub(self.elapsed.get()))
572 }
573
574 fn stop_wheel(&self) {
575 if let Some(mut inner) = self.inner.take() {
577 let mut buckets = mem::take(&mut inner.buckets);
578 for b in &mut buckets {
579 for no in b.entries.drain() {
580 inner.timers[no].bucket = None;
581 }
582 }
583
584 self.flags.set(Flags::empty());
586 self.next_expiry.set(u64::MAX);
587 self.elapsed.set(0);
588 self.elapsed_time.set(None);
589 self.lowres_time.set(None);
590 self.lowres_stime.set(None);
591
592 inner.buckets = buckets;
593 inner.occupied = [0; WHEEL_SIZE];
594 self.inner.set(Some(inner));
595 }
596 }
597}
598
599#[derive(Debug)]
600struct Bucket {
601 lvl: u32,
602 bit: u64,
603 bit_n: u64,
604 entries: Slab<usize>,
605}
606
607impl Bucket {
608 fn add_entry(&mut self, no: usize) -> usize {
609 self.entries.insert(no)
610 }
611}
612
613impl Bucket {
614 fn new(lvl: usize, offs: usize) -> Self {
615 let bit = 1 << (offs as u64);
616 Bucket {
617 bit,
618 lvl: lvl as u32,
619 bit_n: !bit,
620 entries: Slab::default(),
621 }
622 }
623}
624
625#[derive(Debug)]
626struct TimerEntry {
627 bucket: Option<u16>,
628 bucket_entry: usize,
629 task: LocalWaker,
630}
631
632impl TimerEntry {
633 fn complete(&mut self) {
634 if self.bucket.is_some() {
635 self.bucket.take();
636 self.task.wake();
637 }
638 }
639}
640
641struct TimerDriver(Rc<TimerInner>);
642
643impl TimerDriver {
644 fn start(timer: Rc<TimerInner>, inner: &mut TimerMod) {
645 let mut flags = timer.flags.get();
646 flags.insert(Flags::DRIVER_STARTED);
647 timer.flags.set(flags);
648 inner.driver_sleep = Delay::new(Duration::from_millis(timer.next_expiry_ms()));
649
650 crate::spawn(TimerDriver(timer));
651 }
652}
653
654impl Drop for TimerDriver {
655 fn drop(&mut self) {
656 self.0.stop_wheel();
657 }
658}
659
660impl Future for TimerDriver {
661 type Output = ();
662
663 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
664 self.0.driver.register(cx.waker());
665
666 self.0.with_mod(|inner| {
667 let mut flags = self.0.flags.get();
668 if flags.contains(Flags::DRIVER_RECALC) {
669 flags.remove(Flags::DRIVER_RECALC);
670 self.0.flags.set(flags);
671
672 let now = Instant::now();
673 let deadline = if let Some(diff) = now.checked_duration_since(self.0.elapsed_time())
674 {
675 Duration::from_millis(self.0.next_expiry_ms()).saturating_sub(diff)
676 } else {
677 Duration::from_millis(self.0.next_expiry_ms())
678 };
679 inner.driver_sleep.reset(deadline);
680 }
681
682 loop {
683 if Pin::new(&mut inner.driver_sleep).poll(cx).is_ready() {
684 let now = Instant::now();
685 self.0.elapsed.set(self.0.next_expiry.get());
686 self.0.elapsed_time.set(Some(now));
687 self.0.execute_expired_timers(inner);
688
689 if let Some(next_expiry) = self.0.next_pending_bucket(inner) {
690 self.0.next_expiry.set(next_expiry);
691 let dur = Duration::from_millis(self.0.next_expiry_ms());
692 inner.driver_sleep.reset(dur);
693 continue;
694 }
695 self.0.next_expiry.set(u64::MAX);
696 self.0.elapsed_time.set(None);
697 }
698 return Poll::Pending;
699 }
700 })
701 }
702}
703
704struct LowresTimerDriver(Rc<TimerInner>);
705
706impl LowresTimerDriver {
707 fn start(timer: Rc<TimerInner>, inner: &mut TimerMod) {
708 let mut flags = timer.flags.get();
709 flags.insert(Flags::LOWRES_DRIVER);
710 timer.flags.set(flags);
711 inner.lowres_driver_sleep = Delay::new(LOWRES_RESOLUTION);
712
713 crate::spawn(LowresTimerDriver(timer));
714 }
715}
716
717impl Drop for LowresTimerDriver {
718 fn drop(&mut self) {
719 self.0.stop_wheel();
720 }
721}
722
723impl Future for LowresTimerDriver {
724 type Output = ();
725
726 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
727 self.0.lowres_driver.register(cx.waker());
728
729 self.0.with_mod(|inner| {
730 let mut flags = self.0.flags.get();
731 if !flags.contains(Flags::LOWRES_TIMER) {
732 flags.insert(Flags::LOWRES_TIMER);
733 self.0.flags.set(flags);
734 inner.lowres_driver_sleep.reset(LOWRES_RESOLUTION);
735 }
736
737 if Pin::new(&mut inner.lowres_driver_sleep).poll(cx).is_ready() {
738 self.0.lowres_time.set(None);
739 self.0.lowres_stime.set(None);
740 flags.remove(Flags::LOWRES_TIMER);
741 self.0.flags.set(flags);
742 }
743 Poll::Pending
744 })
745 }
746}
747
748#[cfg(test)]
749mod tests {
750 use super::*;
751 use crate::time::{Millis, interval, sleep};
752
753 #[ntex::test]
754 #[allow(unused_variables, clippy::used_underscore_binding)]
755 async fn test_timer() {
756 crate::spawn(async {
757 let s = interval(Millis(25));
758 loop {
759 s.tick().await;
760 }
761 });
762 let time = Instant::now();
763 let fut1 = sleep(Millis(1000));
764 let fut2 = sleep(Millis(200));
765
766 fut2.await;
767 #[cfg(not(target_os = "macos"))]
768 {
769 let _elapsed = time.elapsed();
770 assert!(
771 _elapsed > Duration::from_millis(200) && _elapsed < Duration::from_millis(300),
772 "elapsed: {_elapsed:?}"
773 );
774 }
775
776 fut1.await;
777
778 #[cfg(not(target_os = "macos"))]
779 {
780 let _elapsed = time.elapsed();
781 assert!(
782 _elapsed > Duration::from_secs(1) && _elapsed < Duration::from_millis(1200), "elapsed: {_elapsed:?}",
784 );
785 }
786
787 let time = Instant::now();
788 sleep(Millis(25)).await;
789 #[cfg(not(target_os = "macos"))]
790 {
791 let _elapsed = time.elapsed();
792 assert!(
793 _elapsed > Duration::from_millis(20) && _elapsed < Duration::from_millis(50),
794 "elapsed: {_elapsed:?}",
795 );
796 }
797 }
798}