Skip to content

Commit 8763ffa

Browse files
committed
sleep_until: add platform specific implementations
Except for unix they are all copies of the existing non platform specific implementation. This is the only way since tidy does not allow `#[cfg(target_os = ` in src/thread/mod.rs. Once this is merged more specializations will follow.
1 parent 9b0268a commit 8763ffa

File tree

15 files changed

+200
-20
lines changed

15 files changed

+200
-20
lines changed

library/std/src/sys/pal/hermit/thread.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use super::hermit_abi;
44
use crate::ffi::CStr;
55
use crate::mem::ManuallyDrop;
66
use crate::num::NonZero;
7-
use crate::time::Duration;
7+
use crate::time::{Duration, Instant};
88
use crate::{io, ptr};
99

1010
pub type Tid = hermit_abi::Tid;
@@ -86,6 +86,14 @@ impl Thread {
8686
}
8787
}
8888

89+
pub fn sleep_until(deadline: Instant) {
90+
let now = Instant::now();
91+
92+
if let Some(delay) = deadline.checked_duration_since(now) {
93+
Self::sleep(delay);
94+
}
95+
}
96+
8997
pub fn join(self) {
9098
unsafe {
9199
let _ = hermit_abi::join(self.tid);

library/std/src/sys/pal/itron/thread.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::mem::ManuallyDrop;
1010
use crate::num::NonZero;
1111
use crate::ptr::NonNull;
1212
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
13-
use crate::time::Duration;
13+
use crate::time::{Duration, Instant};
1414
use crate::{hint, io};
1515

1616
pub struct Thread {
@@ -205,6 +205,14 @@ impl Thread {
205205
}
206206
}
207207

208+
pub fn sleep_until(deadline: Instant) {
209+
let now = Instant::now();
210+
211+
if let Some(delay) = deadline.checked_duration_since(now) {
212+
Self::sleep(delay);
213+
}
214+
}
215+
208216
pub fn join(self) {
209217
// Safety: `ThreadInner` is alive at this point
210218
let inner = unsafe { self.p_inner.as_ref() };

library/std/src/sys/pal/sgx/thread.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::unsupported;
55
use crate::ffi::CStr;
66
use crate::io;
77
use crate::num::NonZero;
8-
use crate::time::Duration;
8+
use crate::time::{Duration, Instant};
99

1010
pub struct Thread(task_queue::JoinHandle);
1111

@@ -132,6 +132,14 @@ impl Thread {
132132
usercalls::wait_timeout(0, dur, || true);
133133
}
134134

135+
pub fn sleep_until(deadline: Instant) {
136+
let now = Instant::now();
137+
138+
if let Some(delay) = deadline.checked_duration_since(now) {
139+
Self::sleep(delay);
140+
}
141+
}
142+
135143
pub fn join(self) {
136144
self.0.wait();
137145
}

library/std/src/sys/pal/teeos/thread.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::ffi::CStr;
22
use crate::mem::{self, ManuallyDrop};
33
use crate::num::NonZero;
44
use crate::sys::os;
5-
use crate::time::Duration;
5+
use crate::time::{Duration, Instant};
66
use crate::{cmp, io, ptr};
77

88
pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024;
@@ -109,6 +109,14 @@ impl Thread {
109109
}
110110
}
111111

112+
pub fn sleep_until(deadline: Instant) {
113+
let now = Instant::now();
114+
115+
if let Some(delay) = deadline.checked_duration_since(now) {
116+
Self::sleep(delay);
117+
}
118+
}
119+
112120
/// must join, because no pthread_detach supported
113121
pub fn join(self) {
114122
let id = self.into_id();

library/std/src/sys/pal/uefi/thread.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::ffi::CStr;
33
use crate::io;
44
use crate::num::NonZero;
55
use crate::ptr::NonNull;
6-
use crate::time::Duration;
6+
use crate::time::{Duration, Instant};
77

88
pub struct Thread(!);
99

@@ -39,6 +39,14 @@ impl Thread {
3939
}
4040
}
4141

42+
pub fn sleep_until(deadline: Instant) {
43+
let now = Instant::now();
44+
45+
if let Some(delay) = deadline.checked_duration_since(now) {
46+
Self::sleep(delay);
47+
}
48+
}
49+
4250
pub fn join(self) {
4351
self.0
4452
}

library/std/src/sys/pal/unix/thread.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::sys::weak::dlsym;
66
#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))]
77
use crate::sys::weak::weak;
88
use crate::sys::{os, stack_overflow};
9-
use crate::time::Duration;
9+
use crate::time::{Duration, Instant};
1010
use crate::{cmp, io, ptr};
1111
#[cfg(not(any(
1212
target_os = "l4re",
@@ -296,6 +296,63 @@ impl Thread {
296296
}
297297
}
298298

299+
// Any unix that has clock_nanosleep
300+
#[cfg(any(
301+
target_os = "freebsd",
302+
target_os = "netbsd",
303+
target_os = "linux",
304+
target_os = "android",
305+
target_os = "solaris",
306+
target_os = "illumos",
307+
target_os = "dragonfly",
308+
target_os = "hurd",
309+
target_os = "fuchsia",
310+
target_os = "vxworks",
311+
))]
312+
pub fn sleep_until(deadline: Instant) {
313+
let mut ts = deadline
314+
.into_inner()
315+
.into_timespec()
316+
.to_timespec()
317+
.expect("Timespec is narrower then libc::timespec thus conversion can't fail");
318+
let ts_ptr = &mut ts as *mut _;
319+
320+
// If we're awoken with a signal and the return value is -1
321+
// clock_nanosleep needs to be called again.
322+
unsafe {
323+
while libc::clock_nanosleep(libc::CLOCK_MONOTONIC, libc::TIMER_ABSTIME, ts_ptr, ts_ptr)
324+
== -1
325+
{
326+
assert_eq!(
327+
os::errno(),
328+
libc::EINTR,
329+
"clock nanosleep should only return an error if interrupted"
330+
);
331+
}
332+
}
333+
}
334+
335+
// Any unix that does not have clock_nanosleep
336+
#[cfg(not(any(
337+
target_os = "freebsd",
338+
target_os = "netbsd",
339+
target_os = "linux",
340+
target_os = "android",
341+
target_os = "solaris",
342+
target_os = "illumos",
343+
target_os = "dragonfly",
344+
target_os = "hurd",
345+
target_os = "fuchsia",
346+
target_os = "vxworks",
347+
)))]
348+
pub fn sleep_until(deadline: Instant) {
349+
let now = Instant::now();
350+
351+
if let Some(delay) = deadline.checked_duration_since(now) {
352+
Self::sleep(delay);
353+
}
354+
}
355+
299356
pub fn join(self) {
300357
let id = self.into_id();
301358
let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };

library/std/src/sys/pal/unix/time.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,13 @@ impl Instant {
291291
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
292292
Some(Instant { t: self.t.checked_sub_duration(other)? })
293293
}
294+
295+
// reason for allow(unused): this is needed by the `sleep_until` implementation
296+
// for some unix platforms not all.
297+
#[allow(unused)]
298+
pub(crate) fn into_timespec(self) -> Timespec {
299+
self.t
300+
}
294301
}
295302

296303
impl fmt::Debug for Instant {

library/std/src/sys/pal/unsupported/thread.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ impl Thread {
2626
panic!("can't sleep");
2727
}
2828

29+
pub fn sleep_until(_deadline: Instant) {
30+
panic!("can't sleep");
31+
}
32+
2933
pub fn join(self) {
3034
self.0
3135
}

library/std/src/sys/pal/wasi/thread.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use crate::ffi::CStr;
44
use crate::num::NonZero;
5-
use crate::time::Duration;
5+
use crate::time::{Duration, Instant};
66
use crate::{io, mem};
77

88
cfg_if::cfg_if! {
@@ -171,6 +171,14 @@ impl Thread {
171171
}
172172
}
173173

174+
pub fn sleep_until(deadline: Instant) {
175+
let now = Instant::now();
176+
177+
if let Some(delay) = deadline.checked_duration_since(now) {
178+
Self::sleep(delay);
179+
}
180+
}
181+
174182
pub fn join(self) {
175183
cfg_if::cfg_if! {
176184
if #[cfg(target_feature = "atomics")] {

library/std/src/sys/pal/wasm/atomics/thread.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::ffi::CStr;
22
use crate::io;
33
use crate::num::NonZero;
44
use crate::sys::unsupported;
5-
use crate::time::Duration;
5+
use crate::time::{Duration, Instant};
66

77
pub struct Thread(!);
88

@@ -41,6 +41,14 @@ impl Thread {
4141
}
4242
}
4343

44+
pub fn sleep_until(deadline: Instant) {
45+
let now = Instant::now();
46+
47+
if let Some(delay) = deadline.checked_duration_since(now) {
48+
Self::sleep(delay);
49+
}
50+
}
51+
4452
pub fn join(self) {}
4553
}
4654

library/std/src/sys/pal/windows/thread.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::os::windows::io::{AsRawHandle, HandleOrNull};
88
use crate::sys::handle::Handle;
99
use crate::sys::{c, stack_overflow};
1010
use crate::sys_common::FromInner;
11-
use crate::time::Duration;
11+
use crate::time::{Duration, Instant};
1212
use crate::{io, ptr};
1313

1414
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -106,6 +106,14 @@ impl Thread {
106106
}
107107
}
108108

109+
pub fn sleep_until(deadline: Instant) {
110+
let now = Instant::now();
111+
112+
if let Some(delay) = deadline.checked_duration_since(now) {
113+
Self::sleep(delay);
114+
}
115+
}
116+
109117
pub fn handle(&self) -> &Handle {
110118
&self.handle
111119
}

library/std/src/sys/pal/xous/thread.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::os::xous::ffi::{
88
map_memory, update_memory_flags,
99
};
1010
use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
11-
use crate::time::Duration;
11+
use crate::time::{Duration, Instant};
1212

1313
pub struct Thread {
1414
tid: ThreadId,
@@ -128,6 +128,14 @@ impl Thread {
128128
}
129129
}
130130

131+
pub fn sleep_until(deadline: Instant) {
132+
let now = Instant::now();
133+
134+
if let Some(delay) = deadline.checked_duration_since(now) {
135+
Self::sleep(delay);
136+
}
137+
}
138+
131139
pub fn join(self) {
132140
join_thread(self.tid).unwrap();
133141
}

library/std/src/thread/mod.rs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,33 @@ pub fn sleep(dur: Duration) {
897897
///
898898
/// # Platform-specific behavior
899899
///
900-
/// This function uses [`sleep`] internally, see its platform-specific behavior.
901-
///
900+
/// In most cases this function will call an OS specific function. Where that
901+
/// is not supported [`sleep`] is used. Those platforms are referred to as other
902+
/// in the table below.
903+
///
904+
/// # Underlying System calls
905+
///
906+
/// The following system calls are [currently] being used:
907+
///
908+
/// | Platform | System call |
909+
/// |-----------|----------------------------------------------------------------------|
910+
/// | Linux | [clock_nanosleep] (Monotonic clock) |
911+
/// | BSD except OpenBSD | [clock_nanosleep] (Monotonic Clock)] |
912+
/// | Android | [clock_nanosleep] (Monotonic Clock)] |
913+
/// | Solaris | [clock_nanosleep] (Monotonic Clock)] |
914+
/// | Illumos | [clock_nanosleep] (Monotonic Clock)] |
915+
/// | Dragonfly | [clock_nanosleep] (Monotonic Clock)] |
916+
/// | Hurd | [clock_nanosleep] (Monotonic Clock)] |
917+
/// | Fuchsia | [clock_nanosleep] (Monotonic Clock)] |
918+
/// | Vxworks | [clock_nanosleep] (Monotonic Clock)] |
919+
/// | Other | `sleep_until` uses [`sleep`] and does not issue a syscall itself |
920+
///
921+
/// [currently]: crate::io#platform-specific-behavior
922+
/// [clock_nanosleep]: https://linux.die.net/man/3/clock_nanosleep
923+
/// [subscription_clock]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-subscription_clock-record
924+
/// [mach_wait_until]: https://developer.apple.com/library/archive/technotes/tn2169/_index.html
925+
///
926+
/// **Disclaimer:** These system calls might change over time.
902927
///
903928
/// # Examples
904929
///
@@ -923,9 +948,9 @@ pub fn sleep(dur: Duration) {
923948
/// }
924949
/// ```
925950
///
926-
/// A slow api we must not call too fast and which takes a few
951+
/// A slow API we must not call too fast and which takes a few
927952
/// tries before succeeding. By using `sleep_until` the time the
928-
/// api call takes does not influence when we retry or when we give up
953+
/// API call takes does not influence when we retry or when we give up
929954
///
930955
/// ```no_run
931956
/// #![feature(thread_sleep_until)]
@@ -960,11 +985,7 @@ pub fn sleep(dur: Duration) {
960985
/// ```
961986
#[unstable(feature = "thread_sleep_until", issue = "113752")]
962987
pub fn sleep_until(deadline: Instant) {
963-
let now = Instant::now();
964-
965-
if let Some(delay) = deadline.checked_duration_since(now) {
966-
sleep(delay);
967-
}
988+
imp::Thread::sleep_until(deadline)
968989
}
969990

970991
/// Used to ensure that `park` and `park_timeout` do not unwind, as that can

library/std/src/time.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,13 @@ impl Instant {
407407
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
408408
self.0.checked_sub_duration(&duration).map(Instant)
409409
}
410+
411+
// used by platform specific `sleep_until` implementations.
412+
// reason for #[allow(unused)]: not every platform has a specific `sleep_until`.
413+
#[allow(unused)]
414+
pub(crate) fn into_inner(self) -> time::Instant {
415+
self.0
416+
}
410417
}
411418

412419
#[stable(feature = "time2", since = "1.8.0")]

0 commit comments

Comments
 (0)