madsim/sim/time/
mod.rs

1//! Utilities for tracking time.
2//!
3//!
4
5use crate::rand::{GlobalRng, Rng};
6use futures_util::{select_biased, FutureExt};
7use naive_timer::Timer;
8use spin::Mutex;
9#[doc(no_inline)]
10pub use std::time::{Duration, Instant};
11use std::{future::Future, sync::Arc, time::SystemTime};
12
13pub mod error;
14mod interval;
15mod sleep;
16mod system_time;
17
18pub use self::interval::{interval, interval_at, Interval, MissedTickBehavior};
19pub use self::sleep::{sleep, sleep_until, Sleep};
20
21pub(crate) struct TimeRuntime {
22    handle: TimeHandle,
23}
24
25impl TimeRuntime {
26    pub fn new(rand: &GlobalRng) -> Self {
27        // around 2022
28        let base_time = SystemTime::UNIX_EPOCH
29            + Duration::from_secs(
30                60 * 60 * 24 * 365 * (2022 - 1970)
31                    + rand.with(|rng| rng.gen_range(0..60 * 60 * 24 * 365)),
32            );
33        let handle = TimeHandle {
34            timer: Arc::new(Mutex::new(Timer::default())),
35            clock: Arc::new(Clock::new(base_time)),
36        };
37        TimeRuntime { handle }
38    }
39
40    pub fn handle(&self) -> &TimeHandle {
41        &self.handle
42    }
43
44    /// Advances time to the closest timer event. Returns true if succeed.
45    pub fn advance_to_next_event(&self) -> bool {
46        let mut timer = self.handle.timer.lock();
47        if let Some(mut time) = timer.next() {
48            // WARN: in some platform such as M1 macOS,
49            //       let t0: Instant;
50            //       let t1: Instant;
51            //       t0 + (t1 - t0) < t1 !!
52            // we should add eps to make sure 'now >= deadline' and avoid deadlock
53            time += Duration::from_nanos(50);
54            timer.expire(time);
55            self.handle.clock.set_elapsed(time);
56            true
57        } else {
58            false
59        }
60    }
61
62    #[allow(dead_code)]
63    /// Get the current time.
64    pub fn now_instant(&self) -> Instant {
65        self.handle.now_instant()
66    }
67}
68
69/// Handle to a shared time source.
70#[derive(Clone)]
71pub struct TimeHandle {
72    timer: Arc<Mutex<Timer>>,
73    clock: Arc<Clock>,
74}
75
76impl TimeHandle {
77    /// Returns a `TimeHandle` view over the currently running Runtime.
78    pub fn current() -> Self {
79        crate::context::current(|h| h.time.clone())
80    }
81
82    /// Returns a `TimeHandle` view over the currently running Runtime.
83    pub fn try_current() -> Option<Self> {
84        crate::context::try_current(|h| h.time.clone())
85    }
86
87    /// Return the current time.
88    pub fn now_instant(&self) -> Instant {
89        self.clock.now_instant()
90    }
91
92    /// Return the current time.
93    pub fn now_time(&self) -> SystemTime {
94        self.clock.now_time()
95    }
96
97    /// Returns the amount of time elapsed since this handle was created.
98    pub fn elapsed(&self) -> Duration {
99        self.clock.elapsed()
100    }
101
102    /// Advances time.
103    pub fn advance(&self, duration: Duration) {
104        let time = self.clock.advance(duration);
105        self.timer.lock().expire(time);
106    }
107
108    /// Waits until `duration` has elapsed.
109    ///
110    /// It will sleep for at least 1ms to be consistent with the behavior of `tokio::time::sleep`.
111    pub fn sleep(&self, duration: Duration) -> Sleep {
112        self.sleep_until(self.clock.now_instant() + duration)
113    }
114
115    /// Waits until `deadline` is reached.
116    ///
117    /// It will sleep for at least 1ms to be consistent with the behavior of `tokio::time::sleep_until`.
118    pub fn sleep_until(&self, deadline: Instant) -> Sleep {
119        let min_deadline = self.clock.now_instant() + Duration::from_millis(1);
120        Sleep {
121            handle: self.clone(),
122            deadline: deadline.max(min_deadline),
123        }
124    }
125
126    /// Require a `Future` to complete before the specified duration has elapsed.
127    // TODO: make it Send
128    pub fn timeout<T: Future>(
129        &self,
130        duration: Duration,
131        future: T,
132    ) -> impl Future<Output = Result<T::Output, error::Elapsed>> {
133        let timeout = self.sleep(duration);
134        async move {
135            select_biased! {
136                res = future.fuse() => Ok(res),
137                _ = timeout.fuse() => Err(error::Elapsed),
138            }
139        }
140    }
141
142    pub(crate) fn add_timer_at(
143        &self,
144        deadline: Instant,
145        callback: impl FnOnce() + Send + Sync + 'static,
146    ) {
147        let mut timer = self.timer.lock();
148        timer.add(deadline - self.clock.base_instant(), |_| callback());
149    }
150
151    pub(crate) fn add_timer(&self, dur: Duration, callback: impl FnOnce() + Send + Sync + 'static) {
152        self.add_timer_at(self.clock.now_instant() + dur, callback);
153    }
154}
155
156/// Require a `Future` to complete before the specified duration has elapsed.
157pub fn timeout<T: Future>(
158    duration: Duration,
159    future: T,
160) -> impl Future<Output = Result<T::Output, error::Elapsed>> {
161    let handle = TimeHandle::current();
162    handle.timeout(duration, future)
163}
164
165/// Advances time.
166///
167/// Increments the saved `Instant::now()` value by `duration`.
168/// Subsequent calls to `Instant::now()` will return the result of the increment.
169#[cfg_attr(docsrs, doc(cfg(madsim)))]
170pub fn advance(duration: Duration) {
171    let handle = TimeHandle::current();
172    handle.advance(duration);
173}
174
175struct Clock {
176    inner: Mutex<ClockInner>,
177}
178
179#[derive(Debug)]
180struct ClockInner {
181    /// Time basis for which mock time is derived.
182    base_time: std::time::SystemTime,
183    base_instant: std::time::Instant,
184    /// The amount of mock time which has elapsed.
185    advance: Duration,
186}
187
188impl Clock {
189    fn new(base_time: SystemTime) -> Self {
190        let clock = ClockInner {
191            base_time,
192            base_instant: unsafe { std::mem::zeroed() },
193            advance: Duration::default(),
194        };
195        Clock {
196            inner: Mutex::new(clock),
197        }
198    }
199
200    fn set_elapsed(&self, time: Duration) {
201        let mut inner = self.inner.lock();
202        inner.advance = time;
203    }
204
205    fn elapsed(&self) -> Duration {
206        let inner = self.inner.lock();
207        inner.advance
208    }
209
210    fn advance(&self, duration: Duration) -> Duration {
211        let mut inner = self.inner.lock();
212        inner.advance += duration;
213        inner.advance
214    }
215
216    fn base_instant(&self) -> Instant {
217        let inner = self.inner.lock();
218        inner.base_instant
219    }
220
221    fn now_instant(&self) -> Instant {
222        let inner = self.inner.lock();
223        inner.base_instant + inner.advance
224    }
225
226    fn now_time(&self) -> SystemTime {
227        let inner = self.inner.lock();
228        inner.base_time + inner.advance
229    }
230}
231
232#[cfg(test)]
233mod tests {
234    use super::*;
235    use crate::runtime::Runtime;
236
237    #[test]
238    fn time() {
239        let runtime = Runtime::new();
240        runtime.block_on(async {
241            // sleep for at least 1ms
242            let t0 = Instant::now();
243            sleep(Duration::default()).await;
244            assert!(t0.elapsed() >= Duration::from_millis(1));
245
246            let t0 = Instant::now();
247            sleep_until(t0).await;
248            assert!(t0.elapsed() >= Duration::from_millis(1));
249
250            let t0 = Instant::now();
251
252            sleep(Duration::from_secs(1)).await;
253            assert!(t0.elapsed() >= Duration::from_secs(1));
254
255            sleep_until(t0 + Duration::from_secs(2)).await;
256            assert!(t0.elapsed() >= Duration::from_secs(2));
257
258            assert!(
259                timeout(Duration::from_secs(2), sleep(Duration::from_secs(1)))
260                    .await
261                    .is_ok()
262            );
263            assert!(
264                timeout(Duration::from_secs(1), sleep(Duration::from_secs(2)))
265                    .await
266                    .is_err()
267            );
268        });
269    }
270
271    #[test]
272    fn test_advance() {
273        let runtime = Runtime::new();
274        runtime.block_on(async {
275            let t0 = Instant::now();
276            advance(Duration::from_secs(1));
277            assert!(t0.elapsed() >= Duration::from_secs(1));
278        });
279    }
280}