Skip to content

Commit

Permalink
Auto merge of #113753 - dvdsk:master, r=dtolnay
Browse files Browse the repository at this point in the history
Add implementation for thread::sleep_until

- Feature gate is `thread::sleep_until`
- Tracking issue is: #113752
- APC: rust-lang/libs-team#237
  • Loading branch information
bors committed Sep 17, 2023
2 parents 7d9bce3 + 4cf66f0 commit d7229c4
Showing 1 changed file with 81 additions and 1 deletion.
82 changes: 81 additions & 1 deletion library/std/src/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ use crate::sys_common::thread;
use crate::sys_common::thread_info;
use crate::sys_common::thread_parking::Parker;
use crate::sys_common::{AsInner, IntoInner};
use crate::time::Duration;
use crate::time::{Duration, Instant};

#[stable(feature = "scoped_threads", since = "1.63.0")]
mod scoped;
Expand Down Expand Up @@ -872,6 +872,86 @@ pub fn sleep(dur: Duration) {
imp::Thread::sleep(dur)
}

/// Puts the current thread to sleep until the specified deadline has passed.
///
/// The thread may still be asleep after the deadline specified due to
/// scheduling specifics or platform-dependent functionality. It will never
/// wake before.
///
/// This function is blocking, and should not be used in `async` functions.
///
/// # Platform-specific behavior
///
/// This function uses [`sleep`] internally, see its platform-specific behaviour.
///
///
/// # Examples
///
/// A simple game loop that limits the game to 60 frames per second.
///
/// ```no_run
/// #![feature(thread_sleep_until)]
/// # use std::time::{Duration, Instant};
/// # use std::thread;
/// #
/// # fn update() {}
/// # fn render() {}
/// #
/// let max_fps = 60.0;
/// let frame_time = Duration::from_secs_f32(1.0/max_fps);
/// let mut next_frame = Instant::now();
/// loop {
/// thread::sleep_until(next_frame);
/// next_frame += frame_time;
/// update();
/// render();
/// }
/// ```
///
/// A slow api we must not call too fast and which takes a few
/// tries before succeeding. By using `sleep_until` the time the
/// api call takes does not influence when we retry or when we give up
///
/// ```no_run
/// #![feature(thread_sleep_until)]
/// # use std::time::{Duration, Instant};
/// # use std::thread;
/// #
/// # enum Status {
/// # Ready(usize),
/// # Waiting,
/// # }
/// # fn slow_web_api_call() -> Status { Status::Ready(42) }
/// #
/// # const MAX_DURATION: Duration = Duration::from_secs(10);
/// #
/// # fn try_api_call() -> Result<usize, ()> {
/// let deadline = Instant::now() + MAX_DURATION;
/// let delay = Duration::from_millis(250);
/// let mut next_attempt = Instant::now();
/// loop {
/// if Instant::now() > deadline {
/// break Err(());
/// }
/// if let Status::Ready(data) = slow_web_api_call() {
/// break Ok(data);
/// }
///
/// next_attempt = deadline.min(next_attempt + delay);
/// thread::sleep_until(next_attempt);
/// }
/// # }
/// # let _data = try_api_call();
/// ```
#[unstable(feature = "thread_sleep_until", issue = "113752")]
pub fn sleep_until(deadline: Instant) {
let now = Instant::now();

if let Some(delay) = deadline.checked_duration_since(now) {
sleep(delay);
}
}

/// Used to ensure that `park` and `park_timeout` do not unwind, as that can
/// cause undefined behaviour if not handled correctly (see #102398 for context).
struct PanicGuard;
Expand Down

0 comments on commit d7229c4

Please sign in to comment.