1 #![cfg_attr(not(feature = "rt"), allow(dead_code))]
2 
3 //! Source of time abstraction.
4 //!
5 //! By default, `std::time::Instant::now()` is used. However, when the
6 //! `test-util` feature flag is enabled, the values returned for `now()` are
7 //! configurable.
8 
9 cfg_not_test_util! {
10     use crate::time::{Instant};
11 
12     #[derive(Debug, Clone)]
13     pub(crate) struct Clock {}
14 
15     pub(crate) fn now() -> Instant {
16         Instant::from_std(std::time::Instant::now())
17     }
18 
19     impl Clock {
20         pub(crate) fn new(_enable_pausing: bool, _start_paused: bool) -> Clock {
21             Clock {}
22         }
23 
24         pub(crate) fn now(&self) -> Instant {
25             now()
26         }
27     }
28 }
29 
30 cfg_test_util! {
31     use crate::time::{Duration, Instant};
32     use crate::loom::sync::{Arc, Mutex};
33 
34     cfg_rt! {
35         fn clock() -> Option<Clock> {
36             crate::runtime::context::clock()
37         }
38     }
39 
40     cfg_not_rt! {
41         fn clock() -> Option<Clock> {
42             None
43         }
44     }
45 
46     /// A handle to a source of time.
47     #[derive(Debug, Clone)]
48     pub(crate) struct Clock {
49         inner: Arc<Mutex<Inner>>,
50     }
51 
52     #[derive(Debug)]
53     struct Inner {
54         /// True if the ability to pause time is enabled.
55         enable_pausing: bool,
56 
57         /// Instant to use as the clock's base instant.
58         base: std::time::Instant,
59 
60         /// Instant at which the clock was last unfrozen
61         unfrozen: Option<std::time::Instant>,
62     }
63 
64     /// Pause time
65     ///
66     /// The current value of `Instant::now()` is saved and all subsequent calls
67     /// to `Instant::now()` will return the saved value. The saved value can be
68     /// changed by [`advance`] or by the time auto-advancing once the runtime
69     /// has no work to do. This only affects the `Instant` type in Tokio, and
70     /// the `Instant` in std continues to work as normal.
71     ///
72     /// Pausing time requires the `current_thread` Tokio runtime. This is the
73     /// default runtime used by `#[tokio::test]`. The runtime can be initialized
74     /// with time in a paused state using the `Builder::start_paused` method.
75     ///
76     /// For cases where time is immediately paused, it is better to pause
77     /// the time using the `main` or `test` macro:
78     /// ```
79     /// #[tokio::main(flavor = "current_thread", start_paused = true)]
80     /// async fn main() {
81     ///    println!("Hello world");
82     /// }
83     /// ```
84     ///
85     /// # Panics
86     ///
87     /// Panics if time is already frozen or if called from outside of a
88     /// `current_thread` Tokio runtime.
89     ///
90     /// # Auto-advance
91     ///
92     /// If time is paused and the runtime has no work to do, the clock is
93     /// auto-advanced to the next pending timer. This means that [`Sleep`] or
94     /// other timer-backed primitives can cause the runtime to advance the
95     /// current time when awaited.
96     ///
97     /// [`Sleep`]: crate::time::Sleep
98     /// [`advance`]: crate::time::advance
99     pub fn pause() {
100         let clock = clock().expect("time cannot be frozen from outside the Tokio runtime");
101         clock.pause();
102     }
103 
104     /// Resume time
105     ///
106     /// Clears the saved `Instant::now()` value. Subsequent calls to
107     /// `Instant::now()` will return the value returned by the system call.
108     ///
109     /// # Panics
110     ///
111     /// Panics if time is not frozen or if called from outside of the Tokio
112     /// runtime.
113     pub fn resume() {
114         let clock = clock().expect("time cannot be frozen from outside the Tokio runtime");
115         let mut inner = clock.inner.lock();
116 
117         if inner.unfrozen.is_some() {
118             panic!("time is not frozen");
119         }
120 
121         inner.unfrozen = Some(std::time::Instant::now());
122     }
123 
124     /// Advance time.
125     ///
126     /// Increments the saved `Instant::now()` value by `duration`. Subsequent
127     /// calls to `Instant::now()` will return the result of the increment.
128     ///
129     /// This function will make the current time jump forward by the given
130     /// duration in one jump. This means that all `sleep` calls with a deadline
131     /// before the new time will immediately complete "at the same time", and
132     /// the runtime is free to poll them in any order.  Additionally, this
133     /// method will not wait for the `sleep` calls it advanced past to complete.
134     /// If you want to do that, you should instead call [`sleep`] and rely on
135     /// the runtime's auto-advance feature.
136     ///
137     /// Note that calls to `sleep` are not guaranteed to complete the first time
138     /// they are polled after a call to `advance`. For example, this can happen
139     /// if the runtime has not yet touched the timer driver after the call to
140     /// `advance`. However if they don't, the runtime will poll the task again
141     /// shortly.
142     ///
143     /// # Panics
144     ///
145     /// Panics if time is not frozen or if called from outside of the Tokio
146     /// runtime.
147     ///
148     /// # Auto-advance
149     ///
150     /// If the time is paused and there is no work to do, the runtime advances
151     /// time to the next timer. See [`pause`](pause#auto-advance) for more
152     /// details.
153     ///
154     /// [`sleep`]: fn@crate::time::sleep
155     pub async fn advance(duration: Duration) {
156         let clock = clock().expect("time cannot be frozen from outside the Tokio runtime");
157         clock.advance(duration);
158 
159         crate::task::yield_now().await;
160     }
161 
162     /// Return the current instant, factoring in frozen time.
163     pub(crate) fn now() -> Instant {
164         if let Some(clock) = clock() {
165             clock.now()
166         } else {
167             Instant::from_std(std::time::Instant::now())
168         }
169     }
170 
171     impl Clock {
172         /// Return a new `Clock` instance that uses the current execution context's
173         /// source of time.
174         pub(crate) fn new(enable_pausing: bool, start_paused: bool) -> Clock {
175             let now = std::time::Instant::now();
176 
177             let clock = Clock {
178                 inner: Arc::new(Mutex::new(Inner {
179                     enable_pausing,
180                     base: now,
181                     unfrozen: Some(now),
182                 })),
183             };
184 
185             if start_paused {
186                 clock.pause();
187             }
188 
189             clock
190         }
191 
192         pub(crate) fn pause(&self) {
193             let mut inner = self.inner.lock();
194 
195             if !inner.enable_pausing {
196                 drop(inner); // avoid poisoning the lock
197                 panic!("`time::pause()` requires the `current_thread` Tokio runtime. \
198                         This is the default Runtime used by `#[tokio::test].");
199             }
200 
201             let elapsed = inner.unfrozen.as_ref().expect("time is already frozen").elapsed();
202             inner.base += elapsed;
203             inner.unfrozen = None;
204         }
205 
206         pub(crate) fn is_paused(&self) -> bool {
207             let inner = self.inner.lock();
208             inner.unfrozen.is_none()
209         }
210 
211         pub(crate) fn advance(&self, duration: Duration) {
212             let mut inner = self.inner.lock();
213 
214             if inner.unfrozen.is_some() {
215                 panic!("time is not frozen");
216             }
217 
218             inner.base += duration;
219         }
220 
221         pub(crate) fn now(&self) -> Instant {
222             let inner = self.inner.lock();
223 
224             let mut ret = inner.base;
225 
226             if let Some(unfrozen) = inner.unfrozen {
227                 ret += unfrozen.elapsed();
228             }
229 
230             Instant::from_std(ret)
231         }
232     }
233 }
234