1use super::convert;
3use lazycell::LazyCell;
4use log::trace;
5use mio::Token;
6use slab::Slab;
7use std::{
8 cmp, fmt, io, iter,
9 sync::{
10 Arc,
11 atomic::{AtomicUsize, Ordering},
12 },
13 thread,
14 time::{Duration, Instant},
15};
16use mio_misc::{queue::Notifier, NotificationId};
17
18type Tick = u64;
19
20const TICK_MAX: Tick = u64::MAX;
21
22type WakeupState = Arc<AtomicUsize>;
24
25const TERMINATE_THREAD: usize = 0;
26const EMPTY: Token = Token(usize::MAX);
27
28pub struct Timer<T> {
41 tick_ms: u64,
43 entries: Slab<Entry<T>>,
45 wheel: Vec<WheelEntry>,
48 start: Instant,
50 tick: Tick,
52 next: Token,
54 mask: u64,
56 inner: LazyCell<Inner>,
58}
59
60pub struct Builder {
62 tick: Duration,
64 num_slots: usize,
66 capacity: usize,
68}
69
70impl Builder {
71 pub fn tick_duration(mut self, duration: Duration) -> Builder {
73 self.tick = duration;
74 self
75 }
76
77 pub fn num_slots(mut self, num_slots: usize) -> Builder {
79 self.num_slots = num_slots;
80 self
81 }
82
83 pub fn capacity(mut self, capacity: usize) -> Builder {
85 self.capacity = capacity;
86 self
87 }
88
89 pub fn build<T>(self) -> Timer<T> {
91 Timer::new(
92 convert::millis(self.tick),
93 self.num_slots,
94 self.capacity,
95 Instant::now(),
96 )
97 }
98}
99
100impl Default for Builder {
101 fn default() -> Builder {
102 Builder {
103 tick: Duration::from_millis(100),
104 num_slots: 1 << 8,
105 capacity: 1 << 16,
106 }
107 }
108}
109
110#[derive(Clone, Debug)]
114pub struct Timeout {
115 token: Token,
117 tick: u64,
119}
120
121#[allow(unused)]
122struct Inner {
123 waker: Option<Arc<dyn Notifier>>,
124 waker_id: Option<NotificationId>,
125 wakeup_state: WakeupState,
126 wakeup_thread: thread::JoinHandle<()>,
127}
128
129impl Drop for Inner {
130 fn drop(&mut self) {
131 self.wakeup_state.store(TERMINATE_THREAD, Ordering::Release);
133 self.wakeup_thread.thread().unpark();
135 }
136}
137
138impl fmt::Debug for Inner {
139 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
140 fmt.debug_struct("Inner")
141 .field("wakeup_state", &self.wakeup_state.load(Ordering::Relaxed))
142 .finish()
143 }
144}
145
146#[derive(Copy, Clone, Debug)]
147struct WheelEntry {
148 next_tick: Tick,
149 head: Token,
150}
151
152struct Entry<T> {
155 state: T,
156 links: EntryLinks,
157}
158
159impl<T> Entry<T> {
160 fn new(state: T, tick: u64, next: Token) -> Entry<T> {
161 Entry {
162 state,
163 links: EntryLinks {
164 tick,
165 prev: EMPTY,
166 next,
167 },
168 }
169 }
170}
171
172#[derive(Copy, Clone)]
173struct EntryLinks {
174 tick: Tick,
175 prev: Token,
176 next: Token,
177}
178
179impl<T> Timer<T> {
180 fn new(tick_ms: u64, num_slots: usize, capacity: usize, start: Instant) -> Timer<T> {
181 let num_slots = num_slots.next_power_of_two();
182 let capacity = capacity.next_power_of_two();
183 let mask = (num_slots as u64) - 1;
184 let wheel = iter::repeat(WheelEntry {
185 next_tick: TICK_MAX,
186 head: EMPTY,
187 })
188 .take(num_slots)
189 .collect();
190
191 Timer {
192 tick_ms,
193 entries: Slab::with_capacity(capacity),
194 wheel,
195 start,
196 tick: 0,
197 next: EMPTY,
198 mask,
199 inner: LazyCell::new(),
200 }
201 }
202
203 pub fn set_timeout(&mut self, delay_from_now: Duration, state: T) -> Timeout {
207 let delay_from_start = self.start.elapsed() + delay_from_now;
208 self.set_timeout_at(delay_from_start, state)
209 }
210
211 fn set_timeout_at(&mut self, delay_from_start: Duration, state: T) -> Timeout {
212 let mut tick = duration_to_tick(delay_from_start, self.tick_ms);
213 trace!(
214 "setting timeout; delay={:?}; tick={:?}; current-tick={:?}",
215 delay_from_start, tick, self.tick
216 );
217
218 if tick <= self.tick {
220 tick = self.tick + 1;
221 }
222
223 self.insert(tick, state)
224 }
225
226 fn insert(&mut self, tick: Tick, state: T) -> Timeout {
227 let slot = self.slot_for(tick);
229 let curr = self.wheel[slot];
230
231 let entry = Entry::new(state, tick, curr.head);
233 let token = Token(self.entries.insert(entry));
234
235 if curr.head != EMPTY {
236 self.entries[curr.head.into()].links.prev = token;
239 }
240
241 self.wheel[slot] = WheelEntry {
243 next_tick: cmp::min(tick, curr.next_tick),
244 head: token,
245 };
246
247 self.schedule_readiness(tick);
248
249 trace!("inserted timout; slot={}; token={:?}", slot, token);
250
251 Timeout { token, tick }
253 }
254
255 pub fn cancel_timeout(&mut self, timeout: &Timeout) -> Option<T> {
260 let links = match self.entries.get(timeout.token.into()) {
261 Some(e) => e.links,
262 None => return None,
263 };
264
265 if links.tick != timeout.tick {
267 return None;
268 }
269
270 self.unlink(&links, timeout.token);
271 Some(self.entries.remove(timeout.token.into()).state)
272 }
273
274 pub fn poll(&mut self) -> Option<T> {
279 let target_tick = current_tick(self.start, self.tick_ms);
280 self.poll_to(target_tick)
281 }
282
283 fn poll_to(&mut self, mut target_tick: Tick) -> Option<T> {
284 trace!(
285 "tick_to; target_tick={}; current_tick={}",
286 target_tick, self.tick
287 );
288
289 if target_tick < self.tick {
290 target_tick = self.tick;
291 }
292
293 while self.tick <= target_tick {
294 let curr = self.next;
295
296 trace!("ticking; curr={:?}", curr);
297
298 if curr == EMPTY {
299 self.tick += 1;
300
301 let slot = self.slot_for(self.tick);
302 self.next = self.wheel[slot].head;
303
304 if self.next == EMPTY {
310 self.wheel[slot].next_tick = TICK_MAX;
311 }
312 } else {
313 let slot = self.slot_for(self.tick);
314
315 if curr == self.wheel[slot].head {
316 self.wheel[slot].next_tick = TICK_MAX;
317 }
318
319 let links = self.entries[curr.into()].links;
320
321 if links.tick <= self.tick {
322 trace!("triggering; token={:?}", curr);
323
324 self.unlink(&links, curr);
326
327 return Some(self.entries.remove(curr.into()).state);
329 } else {
330 let next_tick = self.wheel[slot].next_tick;
331 self.wheel[slot].next_tick = cmp::min(next_tick, links.tick);
332 self.next = links.next;
333 }
334 }
335 }
336
337 if let Some(_inner) = self.inner.borrow() {
339 trace!("unsetting readiness");
340 if let Some(tick) = self.next_tick() {
343 self.schedule_readiness(tick);
344 }
345 }
346
347 None
348 }
349
350 fn unlink(&mut self, links: &EntryLinks, token: Token) {
351 trace!(
352 "unlinking timeout; slot={}; token={:?}",
353 self.slot_for(links.tick),
354 token
355 );
356
357 if links.prev == EMPTY {
358 let slot = self.slot_for(links.tick);
359 self.wheel[slot].head = links.next;
360 } else {
361 self.entries[links.prev.into()].links.next = links.next;
362 }
363
364 if links.next != EMPTY {
365 self.entries[links.next.into()].links.prev = links.prev;
366
367 if token == self.next {
368 self.next = links.next;
369 }
370 } else if token == self.next {
371 self.next = EMPTY;
372 }
373 }
374
375 fn schedule_readiness(&self, tick: Tick) {
376 if let Some(inner) = self.inner.borrow() {
377 let mut curr = inner.wakeup_state.load(Ordering::Acquire);
379
380 loop {
381 if curr as Tick <= tick {
382 return;
384 }
385
386 trace!("advancing the wakeup time; target={}; curr={}", tick, curr);
388 let actual = inner
389 .wakeup_state
390 .compare_exchange(curr, tick as usize, Ordering::Release, Ordering::Relaxed)
391 .unwrap_or_else(|x| x);
392
393 if actual == curr {
394 trace!("unparking wakeup thread");
397 inner.wakeup_thread.thread().unpark();
398 return;
399 }
400
401 curr = actual;
402 }
403 }
404 }
405
406 fn next_tick(&self) -> Option<Tick> {
408 if self.next != EMPTY {
409 let slot = self.slot_for(self.entries[self.next.into()].links.tick);
410
411 if self.wheel[slot].next_tick == self.tick {
412 return Some(self.tick);
414 }
415 }
416
417 self.wheel.iter().map(|e| e.next_tick).min()
418 }
419
420 fn slot_for(&self, tick: Tick) -> usize {
421 (self.mask & tick) as usize
422 }
423
424 pub fn register(&mut self, notifier: Arc<dyn Notifier>, notification_id: NotificationId) -> io::Result<()> {
425 if self.inner.borrow().is_some() {
426 return Err(io::Error::new(
427 io::ErrorKind::Other,
428 "timer already registered",
429 ));
430 }
431
432 let wakeup_state = Arc::new(AtomicUsize::new(usize::MAX));
433 let thread_handle = spawn_wakeup_thread(
434 Arc::clone(&wakeup_state),
435 notifier.clone(),
436 notification_id,
437 self.start,
438 self.tick_ms,
439 );
440 self.inner.fill(Inner {
441 waker: Some(notifier),
442 waker_id: Some(notification_id),
443 wakeup_state,
444 wakeup_thread: thread_handle,
445 }).expect("timer already registered");
446
447 if let Some(next_tick) = self.next_tick() {
448 self.schedule_readiness(next_tick);
449 }
450
451 return Ok(())
452 }
453}
454
455impl<T> Default for Timer<T> {
456 fn default() -> Timer<T> {
457 Builder::default().build()
458 }
459}
460
461fn spawn_wakeup_thread(
462 state: WakeupState,
463 waker: Arc<dyn Notifier>,
464 notification_id: NotificationId,
465 start: Instant,
466 tick_ms: u64,
467) -> thread::JoinHandle<()> {
468 thread::spawn(move || {
469 let mut sleep_until_tick = state.load(Ordering::Acquire) as Tick;
470
471 loop {
472 if sleep_until_tick == TERMINATE_THREAD as Tick {
473 return;
474 }
475
476 let now_tick = current_tick(start, tick_ms);
477
478 trace!(
479 "wakeup thread: sleep_until_tick={:?}; now_tick={:?}",
480 sleep_until_tick, now_tick
481 );
482
483 if now_tick < sleep_until_tick {
484 match tick_ms.checked_mul(sleep_until_tick - now_tick) {
489 Some(sleep_duration) => {
490 trace!(
491 "sleeping; tick_ms={}; now_tick={}; sleep_until_tick={}; duration={:?}",
492 tick_ms, now_tick, sleep_until_tick, sleep_duration
493 );
494 thread::park_timeout(Duration::from_millis(sleep_duration));
495 }
496 None => {
497 trace!(
498 "sleeping; tick_ms={}; now_tick={}; blocking sleep",
499 tick_ms, now_tick
500 );
501 thread::park();
502 }
503 }
504 sleep_until_tick = state.load(Ordering::Acquire) as Tick;
505 } else {
506 let actual = state
507 .compare_exchange(
508 sleep_until_tick as usize,
509 usize::MAX,
510 Ordering::AcqRel,
511 Ordering::Acquire,
512 )
513 .unwrap_or_else(|x| x) as Tick;
514
515 if actual == sleep_until_tick {
516 trace!("setting readiness from wakeup thread");
517 let _ = waker.notify(notification_id);
518 sleep_until_tick = usize::MAX as Tick;
519 } else {
520 sleep_until_tick = actual as Tick;
521 }
522 }
523 }
524 })
525}
526
527fn duration_to_tick(elapsed: Duration, tick_ms: u64) -> Tick {
528 let elapsed_ms = convert::millis(elapsed);
530 elapsed_ms.saturating_add(tick_ms / 2) / tick_ms
531}
532
533fn current_tick(start: Instant, tick_ms: u64) -> Tick {
534 duration_to_tick(start.elapsed(), tick_ms)
535}
536
537#[cfg(test)]
538mod test {
539 use super::*;
540 use std::time::{Duration, Instant};
541
542 #[test]
543 pub fn test_timeout_next_tick() {
544 let mut t = timer();
545 let mut tick;
546
547 t.set_timeout_at(Duration::from_millis(100), "a");
548
549 tick = ms_to_tick(&t, 50);
550 assert_eq!(None, t.poll_to(tick));
551
552 tick = ms_to_tick(&t, 100);
553 assert_eq!(Some("a"), t.poll_to(tick));
554 assert_eq!(None, t.poll_to(tick));
555
556 tick = ms_to_tick(&t, 150);
557 assert_eq!(None, t.poll_to(tick));
558
559 tick = ms_to_tick(&t, 200);
560 assert_eq!(None, t.poll_to(tick));
561
562 assert_eq!(count(&t), 0);
563 }
564
565 #[test]
566 pub fn test_clearing_timeout() {
567 let mut t = timer();
568 let mut tick;
569
570 let to = t.set_timeout_at(Duration::from_millis(100), "a");
571 assert_eq!("a", t.cancel_timeout(&to).unwrap());
572
573 tick = ms_to_tick(&t, 100);
574 assert_eq!(None, t.poll_to(tick));
575
576 tick = ms_to_tick(&t, 200);
577 assert_eq!(None, t.poll_to(tick));
578
579 assert_eq!(count(&t), 0);
580 }
581
582 #[test]
583 pub fn test_multiple_timeouts_same_tick() {
584 let mut t = timer();
585 let mut tick;
586
587 t.set_timeout_at(Duration::from_millis(100), "a");
588 t.set_timeout_at(Duration::from_millis(100), "b");
589
590 let mut rcv = vec![];
591
592 tick = ms_to_tick(&t, 100);
593 rcv.push(t.poll_to(tick).unwrap());
594 rcv.push(t.poll_to(tick).unwrap());
595
596 assert_eq!(None, t.poll_to(tick));
597
598 rcv.sort();
599 assert!(rcv == ["a", "b"], "actual={:?}", rcv);
600
601 tick = ms_to_tick(&t, 200);
602 assert_eq!(None, t.poll_to(tick));
603
604 assert_eq!(count(&t), 0);
605 }
606
607 #[test]
608 pub fn test_multiple_timeouts_diff_tick() {
609 let mut t = timer();
610 let mut tick;
611
612 t.set_timeout_at(Duration::from_millis(110), "a");
613 t.set_timeout_at(Duration::from_millis(220), "b");
614 t.set_timeout_at(Duration::from_millis(230), "c");
615 t.set_timeout_at(Duration::from_millis(440), "d");
616 t.set_timeout_at(Duration::from_millis(560), "e");
617
618 tick = ms_to_tick(&t, 100);
619 assert_eq!(Some("a"), t.poll_to(tick));
620 assert_eq!(None, t.poll_to(tick));
621
622 tick = ms_to_tick(&t, 200);
623 assert_eq!(Some("c"), t.poll_to(tick));
624 assert_eq!(Some("b"), t.poll_to(tick));
625 assert_eq!(None, t.poll_to(tick));
626
627 tick = ms_to_tick(&t, 300);
628 assert_eq!(None, t.poll_to(tick));
629
630 tick = ms_to_tick(&t, 400);
631 assert_eq!(Some("d"), t.poll_to(tick));
632 assert_eq!(None, t.poll_to(tick));
633
634 tick = ms_to_tick(&t, 500);
635 assert_eq!(None, t.poll_to(tick));
636
637 tick = ms_to_tick(&t, 600);
638 assert_eq!(Some("e"), t.poll_to(tick));
639 assert_eq!(None, t.poll_to(tick));
640 }
641
642 #[test]
643 pub fn test_catching_up() {
644 let mut t = timer();
645
646 t.set_timeout_at(Duration::from_millis(110), "a");
647 t.set_timeout_at(Duration::from_millis(220), "b");
648 t.set_timeout_at(Duration::from_millis(230), "c");
649 t.set_timeout_at(Duration::from_millis(440), "d");
650
651 let tick = ms_to_tick(&t, 600);
652 assert_eq!(Some("a"), t.poll_to(tick));
653 assert_eq!(Some("c"), t.poll_to(tick));
654 assert_eq!(Some("b"), t.poll_to(tick));
655 assert_eq!(Some("d"), t.poll_to(tick));
656 assert_eq!(None, t.poll_to(tick));
657 }
658
659 #[test]
660 pub fn test_timeout_hash_collision() {
661 let mut t = timer();
662 let mut tick;
663
664 t.set_timeout_at(Duration::from_millis(100), "a");
665 t.set_timeout_at(Duration::from_millis(100 + TICK * SLOTS as u64), "b");
666
667 tick = ms_to_tick(&t, 100);
668 assert_eq!(Some("a"), t.poll_to(tick));
669 assert_eq!(1, count(&t));
670
671 tick = ms_to_tick(&t, 200);
672 assert_eq!(None, t.poll_to(tick));
673 assert_eq!(1, count(&t));
674
675 tick = ms_to_tick(&t, 100 + TICK * SLOTS as u64);
676 assert_eq!(Some("b"), t.poll_to(tick));
677 assert_eq!(0, count(&t));
678 }
679
680 #[test]
681 pub fn test_clearing_timeout_between_triggers() {
682 let mut t = timer();
683 let mut tick;
684
685 let a = t.set_timeout_at(Duration::from_millis(100), "a");
686 let _ = t.set_timeout_at(Duration::from_millis(100), "b");
687 let _ = t.set_timeout_at(Duration::from_millis(200), "c");
688
689 tick = ms_to_tick(&t, 100);
690 assert_eq!(Some("b"), t.poll_to(tick));
691 assert_eq!(2, count(&t));
692
693 t.cancel_timeout(&a);
694 assert_eq!(1, count(&t));
695
696 assert_eq!(None, t.poll_to(tick));
697
698 tick = ms_to_tick(&t, 200);
699 assert_eq!(Some("c"), t.poll_to(tick));
700 assert_eq!(0, count(&t));
701 }
702
703 const TICK: u64 = 100;
704 const SLOTS: usize = 16;
705 const CAPACITY: usize = 32;
706
707 fn count<T>(timer: &Timer<T>) -> usize {
708 timer.entries.len()
709 }
710
711 fn timer() -> Timer<&'static str> {
712 Timer::new(TICK, SLOTS, CAPACITY, Instant::now())
713 }
714
715 fn ms_to_tick<T>(timer: &Timer<T>, ms: u64) -> u64 {
716 ms / timer.tick_ms
717 }
718}