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