robot_bus/runtime/
timers.rs1use std::sync::Arc;
4use std::time::{Duration, Instant};
5
6use crate::runtime::callback_group::CallbackGroup;
7use crate::runtime::worker_pool::WorkerPool;
8
9pub type TimerCallback = Arc<dyn Fn() + Send + Sync>;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub struct TimerHandle {
14 pub(crate) id: u64,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub struct SubscriptionHandle {
20 pub(crate) id: u64,
21}
22
23impl SubscriptionHandle {
24 pub fn id(self) -> u64 {
25 self.id
26 }
27}
28
29pub(crate) struct Timer {
30 pub id: u64,
31 pub period: Duration,
32 pub next_deadline: Instant,
33 pub callback: TimerCallback,
34 pub group: CallbackGroup,
35 pub cancelled: bool,
36}
37
38impl Timer {
39 pub fn new(id: u64, period: Duration, callback: TimerCallback, group: CallbackGroup) -> Self {
40 Self {
41 id,
42 period,
43 next_deadline: Instant::now() + period,
44 callback,
45 group,
46 cancelled: false,
47 }
48 }
49}
50
51pub(crate) fn tick_timers(
55 timers: &mut [Timer],
56 now: Instant,
57 worker_pool: Option<&WorkerPool>,
58) -> bool {
59 let mut fired = false;
60 for timer in timers.iter_mut() {
61 if timer.cancelled || timer.next_deadline > now {
62 continue;
63 }
64 let callback = Arc::clone(&timer.callback);
65 let group = timer.group.clone();
66 group.run(worker_pool, move || callback());
67 timer.next_deadline = now + timer.period;
68 fired = true;
69 }
70 fired
71}
72
73pub(crate) fn ms_until_next_timer(timers: &[Timer], now: Instant) -> Option<i64> {
75 timers
76 .iter()
77 .filter(|t| !t.cancelled)
78 .map(|t| {
79 if t.next_deadline <= now {
80 0
81 } else {
82 t.next_deadline
83 .duration_since(now)
84 .as_millis()
85 .min(i64::MAX as u128) as i64
86 }
87 })
88 .min()
89}
90
91pub(crate) fn effective_poll_timeout_ms(timers: &[Timer], requested_ms: i64, now: Instant) -> i64 {
92 match ms_until_next_timer(timers, now) {
93 Some(until) => until.min(requested_ms.max(0)),
94 None => requested_ms.max(0),
95 }
96}