Coverage Report

Created: 2026-05-30 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.52.3/src/time/clock.rs
Line
Count
Source
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::Mutex;
33
    use crate::loom::sync::atomic::Ordering;
34
    use std::sync::atomic::AtomicBool as StdAtomicBool;
35
36
    cfg_rt! {
37
        #[track_caller]
38
0
        fn with_clock<R>(f: impl FnOnce(Option<&Clock>) -> Result<R, &'static str>) -> R {
39
            use crate::runtime::Handle;
40
41
0
            let res = match Handle::try_current() {
42
0
                Ok(handle) => f(Some(handle.inner.driver().clock())),
43
0
                Err(ref e) if e.is_missing_context() => f(None),
44
0
                Err(_) => panic!("{}", crate::util::error::THREAD_LOCAL_DESTROYED_ERROR),
45
            };
46
47
0
            match res {
48
0
                Ok(ret) => ret,
49
0
                Err(msg) => panic!("{}", msg),
50
            }
51
0
        }
Unexecuted instantiation: tokio::time::clock::with_clock::<tokio::time::instant::Instant, tokio::time::clock::now::{closure#0}>
Unexecuted instantiation: tokio::time::clock::with_clock::<(), tokio::time::clock::advance::{closure#0}::{closure#0}>
Unexecuted instantiation: tokio::time::clock::with_clock::<(), tokio::time::clock::pause::{closure#0}>
Unexecuted instantiation: tokio::time::clock::with_clock::<(), tokio::time::clock::resume::{closure#0}>
52
    }
53
54
    cfg_not_rt! {
55
        #[track_caller]
56
        fn with_clock<R>(f: impl FnOnce(Option<&Clock>) -> Result<R, &'static str>) -> R {
57
            match f(None) {
58
                Ok(ret) => ret,
59
                Err(msg) => panic!("{}", msg),
60
            }
61
        }
62
    }
63
64
    /// A handle to a source of time.
65
    #[derive(Debug)]
66
    pub(crate) struct Clock {
67
        inner: Mutex<Inner>,
68
    }
69
70
    // Used to track if the clock was ever paused. This is an optimization to
71
    // avoid touching the mutex if `test-util` was accidentally enabled in
72
    // release mode.
73
    //
74
    // A static is used so we can avoid accessing the thread-local as well. The
75
    // `std` AtomicBool is used directly because loom does not support static
76
    // atomics.
77
    static DID_PAUSE_CLOCK: StdAtomicBool = StdAtomicBool::new(false);
78
79
    #[derive(Debug)]
80
    struct Inner {
81
        /// True if the ability to pause time is enabled.
82
        enable_pausing: bool,
83
84
        /// Instant to use as the clock's base instant.
85
        base: std::time::Instant,
86
87
        /// Instant at which the clock was last unfrozen.
88
        unfrozen: Option<std::time::Instant>,
89
90
        /// Number of `inhibit_auto_advance` calls still in effect.
91
        auto_advance_inhibit_count: usize,
92
    }
93
94
    /// Pauses time.
95
    ///
96
    /// The current value of `Instant::now()` is saved and all subsequent calls
97
    /// to `Instant::now()` will return the saved value. The saved value can be
98
    /// changed by [`advance`] or by the time auto-advancing once the runtime
99
    /// has no work to do. This only affects the `Instant` type in Tokio, and
100
    /// the `Instant` in std continues to work as normal.
101
    ///
102
    /// Pausing time requires the `current_thread` Tokio runtime. This is the
103
    /// default runtime used by `#[tokio::test]`. The runtime can be initialized
104
    /// with time in a paused state using the `Builder::start_paused` method.
105
    ///
106
    /// For cases where time is immediately paused, it is better to pause
107
    /// the time using the `main` or `test` macro:
108
    /// ```
109
    /// #[tokio::main(flavor = "current_thread", start_paused = true)]
110
    /// async fn main() {
111
    ///    println!("Hello world");
112
    /// }
113
    /// ```
114
    ///
115
    /// # Panics
116
    ///
117
    /// Panics if time is already frozen or if called from outside of a
118
    /// `current_thread` Tokio runtime.
119
    ///
120
    /// # Auto-advance
121
    ///
122
    /// If time is paused and the runtime has no work to do, the clock is
123
    /// auto-advanced to the next pending timer. This means that [`Sleep`] or
124
    /// other timer-backed primitives can cause the runtime to advance the
125
    /// current time when awaited.
126
    ///
127
    /// # Preventing auto-advance
128
    ///
129
    /// In some testing scenarios, you may want to keep the clock paused without
130
    /// auto-advancing, even while waiting for I/O or other asynchronous operations.
131
    /// This can be achieved by using [`spawn_blocking`] to wrap your I/O operations.
132
    ///
133
    /// When a blocking task is running, the clock's auto-advance is temporarily
134
    /// inhibited. This allows you to wait for I/O to complete while keeping the
135
    /// paused clock stationary:
136
    ///
137
    /// ```ignore
138
    /// use tokio::time::{Duration, Instant};
139
    /// use tokio::task;
140
    ///
141
    /// #[tokio::test(start_paused = true)]
142
    /// async fn test_with_io() {
143
    ///     let start = Instant::now();
144
    ///
145
    ///     // The clock will NOT auto-advance while this blocking task runs
146
    ///     let result = task::spawn_blocking(|| {
147
    ///         // Perform I/O operations here
148
    ///         std::thread::sleep(std::time::Duration::from_millis(10));
149
    ///         42
150
    ///     }).await.unwrap();
151
    ///
152
    ///     // Time has not advanced
153
    ///     assert_eq!(start.elapsed(), Duration::ZERO);
154
    /// }
155
    /// ```
156
    ///
157
    /// [`Sleep`]: crate::time::Sleep
158
    /// [`advance`]: crate::time::advance
159
    /// [`spawn_blocking`]: crate::task::spawn_blocking
160
    #[track_caller]
161
0
    pub fn pause() {
162
0
        with_clock(|maybe_clock| {
163
0
            match maybe_clock {
164
0
                Some(clock) => clock.pause(),
165
0
                None => Err("time cannot be frozen from outside the Tokio runtime"),
166
            }
167
0
        });
168
0
    }
169
170
    /// Resumes time.
171
    ///
172
    /// Clears the saved `Instant::now()` value. Subsequent calls to
173
    /// `Instant::now()` will return the value returned by the system call.
174
    ///
175
    /// # Panics
176
    ///
177
    /// Panics if time is not frozen or if called from outside of the Tokio
178
    /// runtime.
179
    #[track_caller]
180
0
    pub fn resume() {
181
0
        with_clock(|maybe_clock| {
182
0
            let clock = match maybe_clock {
183
0
                Some(clock) => clock,
184
0
                None => return Err("time cannot be frozen from outside the Tokio runtime"),
185
            };
186
187
0
            let mut inner = clock.inner.lock();
188
189
0
            if inner.unfrozen.is_some() {
190
0
                return Err("time is not frozen");
191
0
            }
192
193
0
            inner.unfrozen = Some(std::time::Instant::now());
194
0
            Ok(())
195
0
        });
196
0
    }
197
198
    /// Advances time.
199
    ///
200
    /// Increments the saved `Instant::now()` value by `duration`. Subsequent
201
    /// calls to `Instant::now()` will return the result of the increment.
202
    ///
203
    /// This function will make the current time jump forward by the given
204
    /// duration in one jump. This means that all `sleep` calls with a deadline
205
    /// before the new time will immediately complete "at the same time", and
206
    /// the runtime is free to poll them in any order.  Additionally, this
207
    /// method will not wait for the `sleep` calls it advanced past to complete.
208
    /// If you want to do that, you should instead call [`sleep`] and rely on
209
    /// the runtime's auto-advance feature.
210
    ///
211
    /// Note that calls to `sleep` are not guaranteed to complete the first time
212
    /// they are polled after a call to `advance`. For example, this can happen
213
    /// if the runtime has not yet touched the timer driver after the call to
214
    /// `advance`. However if they don't, the runtime will poll the task again
215
    /// shortly.
216
    ///
217
    /// # When to use `sleep` instead
218
    ///
219
    /// **Important:** `advance` is designed for testing scenarios where you want to
220
    /// instantly jump forward in time. However, it has limitations that make it
221
    /// unsuitable for certain use cases:
222
    ///
223
    /// - **Forcing timeouts:** If you want to reliably trigger a timeout, prefer
224
    ///   using [`sleep`] with auto-advance rather than `advance`. The `advance`
225
    ///   function jumps time forward but doesn't guarantee that all timers will be
226
    ///   processed before your code continues.
227
    ///
228
    /// - **Simulating freezes:** If you're trying to simulate a scenario where the
229
    ///   program freezes and then resumes, the batch behavior of `advance` may not
230
    ///   produce the expected results. All timers that expire during the advance
231
    ///   complete simultaneously.
232
    ///
233
    /// For most testing scenarios where you want to wait for a duration to pass
234
    /// and have all timers fire in order, use [`sleep`] instead:
235
    ///
236
    /// ```ignore
237
    /// use tokio::time::{self, Duration};
238
    ///
239
    /// #[tokio::test(start_paused = true)]
240
    /// async fn test_timeout_reliable() {
241
    ///     // Use sleep with auto-advance for reliable timeout testing
242
    ///     time::sleep(Duration::from_secs(5)).await;
243
    ///     // All timers that were scheduled to fire within 5 seconds
244
    ///     // have now been processed in order
245
    /// }
246
    /// ```
247
    ///
248
    /// # Panics
249
    ///
250
    /// Panics if any of the following conditions are met:
251
    ///
252
    /// - The clock is not frozen, which means that you must
253
    ///   call [`pause`] before calling this method.
254
    /// - If called outside of the Tokio runtime.
255
    /// - If the input `duration` is too large (such as [`Duration::MAX`])
256
    ///   to be safely added to the current time without causing an overflow.
257
    ///
258
    /// # Caveats
259
    ///
260
    /// Using a very large `duration` is not recommended,
261
    /// as it may cause panicking due to overflow.
262
    ///
263
    /// # Auto-advance
264
    ///
265
    /// If the time is paused and there is no work to do, the runtime advances
266
    /// time to the next timer. See [`pause`](pause#auto-advance) for more
267
    /// details.
268
    ///
269
    /// [`sleep`]: fn@crate::time::sleep
270
0
    pub async fn advance(duration: Duration) {
271
0
        with_clock(|maybe_clock| {
272
0
            let clock = match maybe_clock {
273
0
                Some(clock) => clock,
274
0
                None => return Err("time cannot be frozen from outside the Tokio runtime"),
275
            };
276
277
0
            clock.advance(duration)
278
0
        });
279
280
0
        crate::task::yield_now().await;
281
0
    }
282
283
    /// Returns the current instant, factoring in frozen time.
284
0
    pub(crate) fn now() -> Instant {
285
0
        if !DID_PAUSE_CLOCK.load(Ordering::Acquire) {
286
0
            return Instant::from_std(std::time::Instant::now());
287
0
        }
288
289
0
        with_clock(|maybe_clock| {
290
0
            Ok(if let Some(clock) = maybe_clock {
291
0
                clock.now()
292
            } else {
293
0
                Instant::from_std(std::time::Instant::now())
294
            })
295
0
        })
296
0
    }
297
298
    impl Clock {
299
        /// Returns a new `Clock` instance that uses the current execution context's
300
        /// source of time.
301
19.0k
        pub(crate) fn new(enable_pausing: bool, start_paused: bool) -> Clock {
302
19.0k
            let now = std::time::Instant::now();
303
304
19.0k
            let clock = Clock {
305
19.0k
                inner: Mutex::new(Inner {
306
19.0k
                    enable_pausing,
307
19.0k
                    base: now,
308
19.0k
                    unfrozen: Some(now),
309
19.0k
                    auto_advance_inhibit_count: 0,
310
19.0k
                }),
311
19.0k
            };
312
313
19.0k
            if start_paused {
314
0
                if let Err(msg) = clock.pause() {
315
0
                    panic!("{}", msg);
316
0
                }
317
19.0k
            }
318
319
19.0k
            clock
320
19.0k
        }
321
322
0
        pub(crate) fn pause(&self) -> Result<(), &'static str> {
323
0
            let mut inner = self.inner.lock();
324
325
0
            if !inner.enable_pausing {
326
0
                return Err("`time::pause()` requires the `current_thread` Tokio runtime. \
327
0
                        This is the default Runtime used by `#[tokio::test].");
328
0
            }
329
330
            // Track that we paused the clock
331
0
            DID_PAUSE_CLOCK.store(true, Ordering::Release);
332
333
0
            let elapsed = match inner.unfrozen.as_ref() {
334
0
                Some(v) => v.elapsed(),
335
0
                None => return Err("time is already frozen")
336
            };
337
0
            inner.base += elapsed;
338
0
            inner.unfrozen = None;
339
340
0
            Ok(())
341
0
        }
342
343
        /// Temporarily stop auto-advancing the clock (see `tokio::time::pause`).
344
0
        pub(crate) fn inhibit_auto_advance(&self) {
345
0
            let mut inner = self.inner.lock();
346
0
            inner.auto_advance_inhibit_count += 1;
347
0
        }
348
349
0
        pub(crate) fn allow_auto_advance(&self) {
350
0
            let mut inner = self.inner.lock();
351
0
            inner.auto_advance_inhibit_count -= 1;
352
0
        }
353
354
0
        pub(crate) fn can_auto_advance(&self) -> bool {
355
0
            let inner = self.inner.lock();
356
0
            inner.unfrozen.is_none() && inner.auto_advance_inhibit_count == 0
357
0
        }
358
359
0
        pub(crate) fn advance(&self, duration: Duration) -> Result<(), &'static str> {
360
0
            let mut inner = self.inner.lock();
361
362
0
            if inner.unfrozen.is_some() {
363
0
                return Err("time is not frozen");
364
0
            }
365
366
0
            inner.base += duration;
367
0
            Ok(())
368
0
        }
369
370
42.5k
        pub(crate) fn now(&self) -> Instant {
371
42.5k
            let inner = self.inner.lock();
372
373
42.5k
            let mut ret = inner.base;
374
375
42.5k
            if let Some(unfrozen) = inner.unfrozen {
376
42.5k
                ret += unfrozen.elapsed();
377
42.5k
            }
378
379
42.5k
            Instant::from_std(ret)
380
42.5k
        }
381
    }
382
}