From 4854fc96463b69174909e56c10805f36bd6d66a9 Mon Sep 17 00:00:00 2001 From: dvdsk Date: Sat, 15 Jul 2023 20:41:27 +0200 Subject: [PATCH 1/4] Adds thread::sleep_until, tracking issue TODO APC (API change proposal): https://github.com/rust-lang/libs-team/issues/237 --- library/std/src/thread/mod.rs | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index e4581c2de78..7cbd7a8a2f6 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -872,6 +872,72 @@ 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 +/// # use std::time::{Duration, Instant}; +/// # use std::thread; +/// # +/// 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 +/// # use std::time::{Duration, Instant}; +/// # use std::thread; +/// # +/// # const MAX_DURATION: Duration = Duration::from_secs(10); +/// # +/// 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 Ready(data) = slow_web_api_call() { +/// break Ok(data), +/// } +/// +/// next_attempt = deadline.min(next_attempt + delay); +/// thread::sleep_until(next_attempt); +/// } +/// ``` +#[unstable(feature = "thread_sleep_until", issue = "todo")] +pub fn sleep_untill(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + thread::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; From 77844f015f0f3277517f1a5f18404d0777a60274 Mon Sep 17 00:00:00 2001 From: dvdsk Date: Sun, 16 Jul 2023 11:32:22 +0200 Subject: [PATCH 2/4] fixes sleep_until examples --- library/std/src/thread/mod.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 7cbd7a8a2f6..35f4cb64178 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -893,6 +893,9 @@ pub fn sleep(dur: Duration) { /// # 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(); @@ -912,6 +915,8 @@ pub fn sleep(dur: Duration) { /// # use std::time::{Duration, Instant}; /// # use std::thread; /// # +/// # fn slow_web_api_call() {} +/// # /// # const MAX_DURATION: Duration = Duration::from_secs(10); /// # /// let deadline = Instant::now() + MAX_DURATION; @@ -919,10 +924,10 @@ pub fn sleep(dur: Duration) { /// let mut next_attempt = Instant::now(); /// loop { /// if Instant::now() > deadline { -/// break Err(()), +/// break Err(()); /// } /// if let Ready(data) = slow_web_api_call() { -/// break Ok(data), +/// break Ok(data); /// } /// /// next_attempt = deadline.min(next_attempt + delay); From bd70b639fde23f599858d81b0ffa8076d2c518bd Mon Sep 17 00:00:00 2001 From: dvdsk Date: Sun, 16 Jul 2023 12:16:04 +0200 Subject: [PATCH 3/4] fix examples add tracking issue --- library/std/src/thread/mod.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 35f4cb64178..9eb3193fd9f 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -178,7 +178,7 @@ 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; @@ -882,14 +882,14 @@ pub fn sleep(dur: Duration) { /// /// # Platform-specific behavior /// -/// This function uses ['sleep'] internally, see its platform-specific behaviour. +/// 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 +/// ```no_run /// # use std::time::{Duration, Instant}; /// # use std::thread; /// # @@ -905,7 +905,7 @@ pub fn sleep(dur: Duration) { /// 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 @@ -915,10 +915,15 @@ pub fn sleep(dur: Duration) { /// # use std::time::{Duration, Instant}; /// # use std::thread; /// # -/// # fn slow_web_api_call() {} +/// # 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 { /// let deadline = Instant::now() + MAX_DURATION; /// let delay = Duration::from_millis(250); /// let mut next_attempt = Instant::now(); @@ -926,20 +931,22 @@ pub fn sleep(dur: Duration) { /// if Instant::now() > deadline { /// break Err(()); /// } -/// if let Ready(data) = slow_web_api_call() { +/// 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 = "todo")] -pub fn sleep_untill(deadline: Instant) { +#[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) { - thread::sleep(delay); + sleep(delay); } } From 4cf66f0b09c6bd917401ef69aea2b287dca49a53 Mon Sep 17 00:00:00 2001 From: dvdsk Date: Sun, 16 Jul 2023 23:35:38 +0200 Subject: [PATCH 4/4] adds crate attribute to examples so they compile --- library/std/src/thread/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 9eb3193fd9f..7b26068c294 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -890,6 +890,7 @@ pub fn sleep(dur: Duration) { /// 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; /// # @@ -912,6 +913,7 @@ pub fn sleep(dur: Duration) { /// 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; /// #