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()` until the timer wheel is checked again will return 68 /// the saved value. Once the timer wheel is checked, time will immediately 69 /// advance to the next registered `Sleep`. This is useful for running tests 70 /// that depend on time. 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 /// # Panics 77 /// 78 /// Panics if time is already frozen or if called from outside of a 79 /// `current_thread` Tokio runtime. 80 /// 81 /// # Auto-advance 82 /// 83 /// If time is paused and the runtime has no work to do, the clock is 84 /// auto-advanced to the next pending timer. This means that [`Sleep`] or 85 /// other timer-backed primitives can cause the runtime to advance the 86 /// current time when awaited. 87 /// 88 /// [`Sleep`]: crate::time::Sleep 89 pub fn pause() { 90 let clock = clock().expect("time cannot be frozen from outside the Tokio runtime"); 91 clock.pause(); 92 } 93 94 /// Resume time 95 /// 96 /// Clears the saved `Instant::now()` value. Subsequent calls to 97 /// `Instant::now()` will return the value returned by the system call. 98 /// 99 /// # Panics 100 /// 101 /// Panics if time is not frozen or if called from outside of the Tokio 102 /// runtime. 103 pub fn resume() { 104 let clock = clock().expect("time cannot be frozen from outside the Tokio runtime"); 105 let mut inner = clock.inner.lock(); 106 107 if inner.unfrozen.is_some() { 108 panic!("time is not frozen"); 109 } 110 111 inner.unfrozen = Some(std::time::Instant::now()); 112 } 113 114 /// Advance time 115 /// 116 /// Increments the saved `Instant::now()` value by `duration`. Subsequent 117 /// calls to `Instant::now()` will return the result of the increment. 118 /// 119 /// # Panics 120 /// 121 /// Panics if time is not frozen or if called from outside of the Tokio 122 /// runtime. 123 /// 124 /// # Auto-advance 125 /// 126 /// If the time is paused and there is no work to do, the runtime advances 127 /// time to the next timer. See [`pause`](pause#auto-advance) for more 128 /// details. 129 pub async fn advance(duration: Duration) { 130 let clock = clock().expect("time cannot be frozen from outside the Tokio runtime"); 131 clock.advance(duration); 132 133 crate::task::yield_now().await; 134 } 135 136 /// Return the current instant, factoring in frozen time. 137 pub(crate) fn now() -> Instant { 138 if let Some(clock) = clock() { 139 clock.now() 140 } else { 141 Instant::from_std(std::time::Instant::now()) 142 } 143 } 144 145 impl Clock { 146 /// Return a new `Clock` instance that uses the current execution context's 147 /// source of time. 148 pub(crate) fn new(enable_pausing: bool, start_paused: bool) -> Clock { 149 let now = std::time::Instant::now(); 150 151 let clock = Clock { 152 inner: Arc::new(Mutex::new(Inner { 153 enable_pausing, 154 base: now, 155 unfrozen: Some(now), 156 })), 157 }; 158 159 if start_paused { 160 clock.pause(); 161 } 162 163 clock 164 } 165 166 pub(crate) fn pause(&self) { 167 let mut inner = self.inner.lock(); 168 169 if !inner.enable_pausing { 170 drop(inner); // avoid poisoning the lock 171 panic!("`time::pause()` requires the `current_thread` Tokio runtime. \ 172 This is the default Runtime used by `#[tokio::test]."); 173 } 174 175 let elapsed = inner.unfrozen.as_ref().expect("time is already frozen").elapsed(); 176 inner.base += elapsed; 177 inner.unfrozen = None; 178 } 179 180 pub(crate) fn is_paused(&self) -> bool { 181 let inner = self.inner.lock(); 182 inner.unfrozen.is_none() 183 } 184 185 pub(crate) fn advance(&self, duration: Duration) { 186 let mut inner = self.inner.lock(); 187 188 if inner.unfrozen.is_some() { 189 panic!("time is not frozen"); 190 } 191 192 inner.base += duration; 193 } 194 195 pub(crate) fn now(&self) -> Instant { 196 let inner = self.inner.lock(); 197 198 let mut ret = inner.base; 199 200 if let Some(unfrozen) = inner.unfrozen { 201 ret += unfrozen.elapsed(); 202 } 203 204 Instant::from_std(ret) 205 } 206 } 207 } 208