Coverage Report

Created: 2026-11-12 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.54.1/src/time/sleep.rs
Line
Count
Source
1
use crate::runtime::{scheduler, Timer};
2
use crate::time::{error::Error, safe_delay, Duration, Instant};
3
use crate::util::trace;
4
5
use pin_project_lite::pin_project;
6
use std::future::Future;
7
use std::panic::Location;
8
use std::pin::Pin;
9
use std::task::{self, ready, Poll};
10
11
/// Waits until `deadline` is reached.
12
///
13
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
14
/// operates at millisecond granularity and should not be used for tasks that
15
/// require high-resolution timers.
16
///
17
/// To run something regularly on a schedule, see [`interval`].
18
///
19
/// # Cancellation
20
///
21
/// Canceling a sleep instance is done by dropping the returned future. No additional
22
/// cleanup work is required.
23
///
24
/// # Examples
25
///
26
/// Wait 100ms and print "100 ms have elapsed".
27
///
28
/// ```
29
/// use tokio::time::{sleep_until, Instant, Duration};
30
///
31
/// # #[tokio::main(flavor = "current_thread")]
32
/// # async fn main() {
33
/// sleep_until(Instant::now() + Duration::from_millis(100)).await;
34
/// println!("100 ms have elapsed");
35
/// # }
36
/// ```
37
///
38
/// See the documentation for the [`Sleep`] type for more examples.
39
///
40
/// # Panics
41
///
42
/// This function panics if there is no current timer set.
43
///
44
/// It can be triggered when [`Builder::enable_time`] or
45
/// [`Builder::enable_all`] are not included in the builder.
46
///
47
/// It can also panic whenever a timer is created outside of a
48
/// Tokio runtime. That is why `rt.block_on(sleep(...))` will panic,
49
/// since the function is executed outside of the runtime.
50
/// Whereas `rt.block_on(async {sleep(...).await})` doesn't panic.
51
/// And this is because wrapping the function on an async makes it lazy,
52
/// and so gets executed inside the runtime successfully without
53
/// panicking.
54
///
55
/// [`Sleep`]: struct@crate::time::Sleep
56
/// [`interval`]: crate::time::interval()
57
/// [`Builder::enable_time`]: crate::runtime::Builder::enable_time
58
/// [`Builder::enable_all`]: crate::runtime::Builder::enable_all
59
// Alias for old name in 0.x
60
#[cfg_attr(docsrs, doc(alias = "delay_until"))]
61
#[track_caller]
62
0
pub fn sleep_until(deadline: Instant) -> Sleep {
63
0
    Sleep::new_timeout(deadline, trace::caller_location())
64
0
}
65
66
/// Waits until `duration` has elapsed.
67
///
68
/// Equivalent to `sleep_until(Instant::now() + duration)`. An asynchronous
69
/// analog to `std::thread::sleep`.
70
///
71
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
72
/// operates at millisecond granularity and should not be used for tasks that
73
/// require high-resolution timers. The implementation is platform specific,
74
/// and some platforms (specifically Windows) will provide timers with a
75
/// larger resolution than 1 ms.
76
///
77
/// To run something regularly on a schedule, see [`interval`].
78
///
79
/// # Cancellation
80
///
81
/// Canceling a sleep instance is done by dropping the returned future. No additional
82
/// cleanup work is required.
83
///
84
/// # Examples
85
///
86
/// Wait 100ms and print "100 ms have elapsed".
87
///
88
/// ```
89
/// use tokio::time::{sleep, Duration};
90
///
91
/// # #[tokio::main(flavor = "current_thread")]
92
/// # async fn main() {
93
/// sleep(Duration::from_millis(100)).await;
94
/// println!("100 ms have elapsed");
95
/// # }
96
/// ```
97
///
98
/// See the documentation for the [`Sleep`] type for more examples.
99
///
100
/// # Panics
101
///
102
/// This function panics if there is no current timer set.
103
///
104
/// It can be triggered when [`Builder::enable_time`] or
105
/// [`Builder::enable_all`] are not included in the builder.
106
///
107
/// It can also panic whenever a timer is created outside of a
108
/// Tokio runtime. That is why `rt.block_on(sleep(...))` will panic,
109
/// since the function is executed outside of the runtime.
110
/// Whereas `rt.block_on(async {sleep(...).await})` doesn't panic.
111
/// And this is because wrapping the function on an async makes it lazy,
112
/// and so gets executed inside the runtime successfully without
113
/// panicking.
114
///
115
/// [`Sleep`]: struct@crate::time::Sleep
116
/// [`interval`]: crate::time::interval()
117
/// [`Builder::enable_time`]: crate::runtime::Builder::enable_time
118
/// [`Builder::enable_all`]: crate::runtime::Builder::enable_all
119
// Alias for old name in 0.x
120
#[cfg_attr(docsrs, doc(alias = "delay_for"))]
121
#[cfg_attr(docsrs, doc(alias = "wait"))]
122
#[track_caller]
123
0
pub fn sleep(duration: Duration) -> Sleep {
124
0
    let deadline = Instant::now() + safe_delay(duration);
125
0
    Sleep::new_timeout(deadline, trace::caller_location())
126
0
}
127
128
pin_project! {
129
    /// Future returned by [`sleep`](sleep) and [`sleep_until`](sleep_until).
130
    ///
131
    /// This type does not implement the `Unpin` trait, which means that if you
132
    /// use it with [`select!`] or by calling `poll`, you have to pin it first.
133
    /// If you use it with `.await`, this does not apply.
134
    ///
135
    /// # Examples
136
    ///
137
    /// Wait 100ms and print "100 ms have elapsed".
138
    ///
139
    /// ```
140
    /// use tokio::time::{sleep, Duration};
141
    ///
142
    /// # #[tokio::main(flavor = "current_thread")]
143
    /// # async fn main() {
144
    /// sleep(Duration::from_millis(100)).await;
145
    /// println!("100 ms have elapsed");
146
    /// # }
147
    /// ```
148
    ///
149
    /// Use with [`select!`]. Pinning the `Sleep` with [`tokio::pin!`] is
150
    /// necessary when the same `Sleep` is selected on multiple times.
151
    /// ```no_run
152
    /// use tokio::time::{self, Duration, Instant};
153
    ///
154
    /// # #[tokio::main(flavor = "current_thread")]
155
    /// # async fn main() {
156
    /// let sleep = time::sleep(Duration::from_millis(10));
157
    /// tokio::pin!(sleep);
158
    ///
159
    /// loop {
160
    ///     tokio::select! {
161
    ///         () = &mut sleep => {
162
    ///             println!("timer elapsed");
163
    ///             sleep.as_mut().reset(Instant::now() + Duration::from_millis(50));
164
    ///         },
165
    ///     }
166
    /// }
167
    /// # }
168
    /// ```
169
    /// Use in a struct with boxing. By pinning the `Sleep` with a `Box`, the
170
    /// `HasSleep` struct implements `Unpin`, even though `Sleep` does not.
171
    /// ```
172
    /// use std::future::Future;
173
    /// use std::pin::Pin;
174
    /// use std::task::{Context, Poll};
175
    /// use tokio::time::Sleep;
176
    ///
177
    /// struct HasSleep {
178
    ///     sleep: Pin<Box<Sleep>>,
179
    /// }
180
    ///
181
    /// impl Future for HasSleep {
182
    ///     type Output = ();
183
    ///
184
    ///     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
185
    ///         self.sleep.as_mut().poll(cx)
186
    ///     }
187
    /// }
188
    /// ```
189
    /// Use in a struct with pin projection. This method avoids the `Box`, but
190
    /// the `HasSleep` struct will not be `Unpin` as a consequence.
191
    /// ```
192
    /// use std::future::Future;
193
    /// use std::pin::Pin;
194
    /// use std::task::{Context, Poll};
195
    /// use tokio::time::Sleep;
196
    /// use pin_project_lite::pin_project;
197
    ///
198
    /// pin_project! {
199
    ///     struct HasSleep {
200
    ///         #[pin]
201
    ///         sleep: Sleep,
202
    ///     }
203
    /// }
204
    ///
205
    /// impl Future for HasSleep {
206
    ///     type Output = ();
207
    ///
208
    ///     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
209
    ///         self.project().sleep.poll(cx)
210
    ///     }
211
    /// }
212
    /// ```
213
    ///
214
    /// [`select!`]: ../macro.select.html
215
    /// [`tokio::pin!`]: ../macro.pin.html
216
    #[project(!Unpin)]
217
    // Alias for old name in 0.2
218
    #[cfg_attr(docsrs, doc(alias = "Delay"))]
219
    #[derive(Debug)]
220
    #[must_use = "futures do nothing unless you `.await` or poll them"]
221
    pub struct Sleep {
222
        deadline: Instant,
223
        driver: scheduler::Handle,
224
        inner: Inner,
225
        #[pin]
226
        timer: Option<Timer>,
227
    }
228
}
229
230
cfg_trace! {
231
    #[derive(Debug)]
232
    struct Inner {
233
        ctx: trace::AsyncOpTracingCtx,
234
    }
235
}
236
237
cfg_not_trace! {
238
    #[derive(Debug)]
239
    struct Inner {
240
    }
241
}
242
243
impl Sleep {
244
    #[cfg_attr(not(all(tokio_unstable, feature = "tracing")), allow(unused_variables))]
245
    #[track_caller]
246
0
    pub(crate) fn new_timeout(
247
0
        deadline: Instant,
248
0
        location: Option<&'static Location<'static>>,
249
0
    ) -> Sleep {
250
0
        let handle = scheduler::Handle::current();
251
        // Panic if the time driver is not enabled (backwards compat)
252
0
        _ = handle.driver().time();
253
        #[cfg(all(tokio_unstable, feature = "tracing"))]
254
        let inner = {
255
            let location = location.expect("should have location if tracing");
256
            let resource_span = tracing::trace_span!(
257
                parent: None,
258
                "runtime.resource",
259
                concrete_type = "Sleep",
260
                kind = "timer",
261
                loc.file = location.file(),
262
                loc.line = location.line(),
263
                loc.col = location.column(),
264
            );
265
266
            let async_op_span = tracing::trace_span!(
267
                parent: &resource_span,
268
                "runtime.resource.async_op",
269
                source = "Sleep::new_timeout",
270
            );
271
272
            let async_op_poll_span =
273
                tracing::trace_span!(parent: &async_op_span, "runtime.resource.async_op.poll");
274
275
            let ctx = trace::AsyncOpTracingCtx {
276
                async_op_span,
277
                async_op_poll_span,
278
                resource_span,
279
            };
280
281
            Inner { ctx }
282
        };
283
284
        #[cfg(not(all(tokio_unstable, feature = "tracing")))]
285
0
        let inner = Inner {};
286
287
0
        Sleep {
288
0
            deadline,
289
0
            driver: handle,
290
0
            inner,
291
0
            timer: None,
292
0
        }
293
0
    }
294
295
    /// Returns the instant at which the future will complete.
296
0
    pub fn deadline(&self) -> Instant {
297
0
        self.deadline
298
0
    }
299
300
    /// Returns `true` if `Sleep` has elapsed.
301
    ///
302
    /// A `Sleep` instance is elapsed when the requested duration has elapsed.
303
0
    pub fn is_elapsed(&self) -> bool {
304
0
        self.timer.as_ref().is_some_and(Timer::is_elapsed)
305
0
    }
306
307
    /// Resets the `Sleep` instance to a new deadline.
308
    ///
309
    /// Calling this function allows changing the instant at which the `Sleep`
310
    /// future completes without having to create new associated state.
311
    ///
312
    /// This function can be called both before and after the future has
313
    /// completed.
314
    ///
315
    /// To call this method, you will usually combine the call with
316
    /// [`Pin::as_mut`], which lets you call the method without consuming the
317
    /// `Sleep` itself.
318
    ///
319
    /// # Example
320
    ///
321
    /// ```
322
    /// use tokio::time::{Duration, Instant};
323
    ///
324
    /// # #[tokio::main(flavor = "current_thread")]
325
    /// # async fn main() {
326
    /// let sleep = tokio::time::sleep(Duration::from_millis(10));
327
    /// tokio::pin!(sleep);
328
    ///
329
    /// sleep.as_mut().reset(Instant::now() + Duration::from_millis(20));
330
    /// # }
331
    /// ```
332
    ///
333
    /// See also the top-level examples.
334
    ///
335
    /// [`Pin::as_mut`]: fn@std::pin::Pin::as_mut
336
0
    pub fn reset(self: Pin<&mut Self>, deadline: Instant) {
337
0
        let mut this = self.project();
338
0
        *this.deadline = deadline;
339
340
0
        let handle = this.driver;
341
0
        let time_source = handle.driver().time().time_source();
342
0
        let deadline = time_source.deadline_to_tick(deadline);
343
344
        #[cfg(all(tokio_unstable, feature = "tracing"))]
345
        {
346
            let _resource_enter = this.inner.ctx.resource_span.enter();
347
            this.inner.ctx.async_op_span =
348
                tracing::trace_span!("runtime.resource.async_op", source = "Sleep::reset");
349
            let _async_op_enter = this.inner.ctx.async_op_span.enter();
350
351
            this.inner.ctx.async_op_poll_span =
352
                tracing::trace_span!("runtime.resource.async_op.poll");
353
354
            let clock = handle.driver().clock();
355
            let now = time_source.now(clock);
356
            tracing::trace!(
357
                target: "runtime::resource::state_update",
358
                duration = deadline.saturating_sub(now),
359
                duration.unit = "ms",
360
                duration.op = "override",
361
            );
362
        }
363
364
0
        match this.timer.as_mut().as_pin_mut() {
365
0
            Some(timer) => timer.reset(handle.clone(), deadline),
366
0
            None => {
367
0
                let timer = Timer::new(handle.clone(), deadline);
368
0
                this.timer.set(Some(timer));
369
0
                this.timer.as_pin_mut().unwrap().init(deadline);
370
0
            }
371
        }
372
0
    }
373
374
    /// Resets the `Sleep` instance to a new deadline.
375
    ///
376
    /// Unlike [`reset`][Self::reset], this __removes__ the internal timer.
377
0
    pub(super) fn reset_without_timer(self: Pin<&mut Self>, deadline: Instant) {
378
0
        let mut this = self.project();
379
0
        *this.deadline = deadline;
380
0
        this.timer.set(None);
381
0
    }
382
383
0
    fn poll_elapsed(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<(), Error>> {
384
0
        ready!(crate::trace::trace_leaf(cx));
385
0
        let mut this = self.project();
386
387
        #[cfg(all(tokio_unstable, feature = "tracing"))]
388
        let _res_span = this.inner.ctx.resource_span.enter();
389
        #[cfg(all(tokio_unstable, feature = "tracing"))]
390
        let _ao_span = this.inner.ctx.async_op_span.enter();
391
        #[cfg(all(tokio_unstable, feature = "tracing"))]
392
        let _ao_poll_span = this.inner.ctx.async_op_poll_span.enter();
393
394
        // Keep track of task budget
395
        #[cfg(all(tokio_unstable, feature = "tracing"))]
396
        let coop = ready!(trace_poll_op!(
397
            "poll_elapsed",
398
            crate::task::coop::poll_proceed(cx),
399
        ));
400
401
        #[cfg(any(not(tokio_unstable), not(feature = "tracing")))]
402
0
        let coop = ready!(crate::task::coop::poll_proceed(cx));
403
404
0
        let timer = match this.timer.as_mut().as_pin_mut() {
405
0
            Some(timer) => timer,
406
            None => {
407
0
                let handle = this.driver;
408
0
                let time_source = handle.driver().time().time_source();
409
0
                let deadline = time_source.deadline_to_tick(*this.deadline);
410
411
                #[cfg(all(tokio_unstable, feature = "tracing"))]
412
                {
413
                    let clock = handle.driver().clock();
414
                    let now = time_source.now(clock);
415
                    tracing::trace!(
416
                        target: "runtime::resource::state_update",
417
                        duration = deadline.saturating_sub(now),
418
                        duration.unit = "ms",
419
                        duration.op = "override",
420
                    );
421
                }
422
423
0
                let timer = Timer::new(handle.clone(), deadline);
424
0
                this.timer.set(Some(timer));
425
0
                let mut timer = this.timer.as_pin_mut().unwrap();
426
0
                timer.as_mut().init(deadline);
427
0
                timer
428
            }
429
        };
430
431
0
        let result = timer.poll_elapsed(cx).map(move |r| {
432
0
            coop.made_progress();
433
0
            r
434
0
        });
435
436
        #[cfg(all(tokio_unstable, feature = "tracing"))]
437
        return trace_poll_op!("poll_elapsed", result);
438
439
        #[cfg(any(not(tokio_unstable), not(feature = "tracing")))]
440
0
        return result;
441
0
    }
442
}
443
444
impl Future for Sleep {
445
    type Output = ();
446
447
    // `poll_elapsed` can return an error in two cases:
448
    //
449
    // - AtCapacity: this is a pathological case where far too many
450
    //   sleep instances have been scheduled.
451
    // - Shutdown: No timer has been setup, which is a misuse error.
452
    //
453
    // Both cases are extremely rare, and pretty accurately fit into
454
    // "logic errors", so we just panic in this case. A user couldn't
455
    // really do much better if we passed the error onwards.
456
0
    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
457
0
        match ready!(self.poll_elapsed(cx)) {
458
0
            Ok(()) => Poll::Ready(()),
459
0
            Err(e) => panic!("timer error: {e}"),
460
        }
461
0
    }
462
}