Skip to content

Commit d7229c4

Browse files
committed
Auto merge of #113753 - dvdsk:master, r=dtolnay
Add implementation for thread::sleep_until - Feature gate is `thread::sleep_until` - Tracking issue is: #113752 - APC: rust-lang/libs-team#237
2 parents 7d9bce3 + 4cf66f0 commit d7229c4

File tree

1 file changed

+81
-1
lines changed

1 file changed

+81
-1
lines changed

library/std/src/thread/mod.rs

+81-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ use crate::sys_common::thread;
178178
use crate::sys_common::thread_info;
179179
use crate::sys_common::thread_parking::Parker;
180180
use crate::sys_common::{AsInner, IntoInner};
181-
use crate::time::Duration;
181+
use crate::time::{Duration, Instant};
182182

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

875+
/// Puts the current thread to sleep until the specified deadline has passed.
876+
///
877+
/// The thread may still be asleep after the deadline specified due to
878+
/// scheduling specifics or platform-dependent functionality. It will never
879+
/// wake before.
880+
///
881+
/// This function is blocking, and should not be used in `async` functions.
882+
///
883+
/// # Platform-specific behavior
884+
///
885+
/// This function uses [`sleep`] internally, see its platform-specific behaviour.
886+
///
887+
///
888+
/// # Examples
889+
///
890+
/// A simple game loop that limits the game to 60 frames per second.
891+
///
892+
/// ```no_run
893+
/// #![feature(thread_sleep_until)]
894+
/// # use std::time::{Duration, Instant};
895+
/// # use std::thread;
896+
/// #
897+
/// # fn update() {}
898+
/// # fn render() {}
899+
/// #
900+
/// let max_fps = 60.0;
901+
/// let frame_time = Duration::from_secs_f32(1.0/max_fps);
902+
/// let mut next_frame = Instant::now();
903+
/// loop {
904+
/// thread::sleep_until(next_frame);
905+
/// next_frame += frame_time;
906+
/// update();
907+
/// render();
908+
/// }
909+
/// ```
910+
///
911+
/// A slow api we must not call too fast and which takes a few
912+
/// tries before succeeding. By using `sleep_until` the time the
913+
/// api call takes does not influence when we retry or when we give up
914+
///
915+
/// ```no_run
916+
/// #![feature(thread_sleep_until)]
917+
/// # use std::time::{Duration, Instant};
918+
/// # use std::thread;
919+
/// #
920+
/// # enum Status {
921+
/// # Ready(usize),
922+
/// # Waiting,
923+
/// # }
924+
/// # fn slow_web_api_call() -> Status { Status::Ready(42) }
925+
/// #
926+
/// # const MAX_DURATION: Duration = Duration::from_secs(10);
927+
/// #
928+
/// # fn try_api_call() -> Result<usize, ()> {
929+
/// let deadline = Instant::now() + MAX_DURATION;
930+
/// let delay = Duration::from_millis(250);
931+
/// let mut next_attempt = Instant::now();
932+
/// loop {
933+
/// if Instant::now() > deadline {
934+
/// break Err(());
935+
/// }
936+
/// if let Status::Ready(data) = slow_web_api_call() {
937+
/// break Ok(data);
938+
/// }
939+
///
940+
/// next_attempt = deadline.min(next_attempt + delay);
941+
/// thread::sleep_until(next_attempt);
942+
/// }
943+
/// # }
944+
/// # let _data = try_api_call();
945+
/// ```
946+
#[unstable(feature = "thread_sleep_until", issue = "113752")]
947+
pub fn sleep_until(deadline: Instant) {
948+
let now = Instant::now();
949+
950+
if let Some(delay) = deadline.checked_duration_since(now) {
951+
sleep(delay);
952+
}
953+
}
954+
875955
/// Used to ensure that `park` and `park_timeout` do not unwind, as that can
876956
/// cause undefined behaviour if not handled correctly (see #102398 for context).
877957
struct PanicGuard;

0 commit comments

Comments
 (0)