Skip to content

Commit 3a1d38f

Browse files
committed
adds specialized impl of sleep_until for unix and wasi
1 parent 6b9676b commit 3a1d38f

File tree

13 files changed

+147
-40
lines changed

13 files changed

+147
-40
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ impl Thread {
131131
usercalls::wait_timeout(0, dur, || true);
132132
}
133133

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

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,54 @@ impl Thread {
303303
}
304304
}
305305

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

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@ impl Instant {
287287
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
288288
Some(Instant { t: self.t.checked_sub_duration(other)? })
289289
}
290+
291+
pub(in crate::sys::unix) fn into_timespec(self) -> Timespec {
292+
self.t
293+
}
290294
}
291295

292296
impl fmt::Debug for Instant {

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

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::ffi::CStr;
44
use crate::num::NonZero;
55
use crate::sys::unsupported;
6-
use crate::time::Duration;
6+
use crate::time::{Duration, Instant};
77
use crate::{io, mem};
88

99
cfg_if::cfg_if! {
@@ -136,41 +136,25 @@ impl Thread {
136136
}
137137

138138
pub fn sleep(dur: Duration) {
139-
let mut nanos = dur.as_nanos();
139+
let mut nanos_all = dur.as_nanos();
140140
while nanos > 0 {
141-
const USERDATA: wasi::Userdata = 0x0123_45678;
142-
143-
let clock = wasi::SubscriptionClock {
144-
id: wasi::CLOCKID_MONOTONIC,
145-
timeout: u64::try_from(nanos).unwrap_or(u64::MAX),
146-
precision: 0,
147-
flags: 0,
148-
};
149-
nanos -= u128::from(clock.timeout);
150-
151-
let in_ = wasi::Subscription {
152-
userdata: USERDATA,
153-
u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
154-
};
155-
unsafe {
156-
let mut event: wasi::Event = mem::zeroed();
157-
let res = wasi::poll_oneoff(&in_, &mut event, 1);
158-
match (res, event) {
159-
(
160-
Ok(1),
161-
wasi::Event {
162-
userdata: USERDATA,
163-
error: wasi::ERRNO_SUCCESS,
164-
type_: wasi::EVENTTYPE_CLOCK,
165-
..
166-
},
167-
) => {}
168-
_ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
169-
}
170-
}
141+
let nanos_sleepable = u64::try_from(full_nanos).unwrap_or(u64::MAX);
142+
nanos_all -= u128::from(nanos_sleepable);
143+
sleep_with(nanos_sleepable, wasi::CLOCKID_MONOTONIC, 0);
171144
}
172145
}
173146

147+
pub fn sleep_until(deadline: Instant) {
148+
let nanos = deadline.into_inner().into_inner().as_nanos();
149+
assert!(nanos <= u64::MAX as u128);
150+
151+
sleep_with(
152+
nanos as u64,
153+
wasi::CLOCKID_MONOTONIC,
154+
wasi::SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME,
155+
);
156+
}
157+
174158
pub fn join(self) {
175159
cfg_if::cfg_if! {
176160
if #[cfg(target_feature = "atomics")] {
@@ -186,6 +170,33 @@ impl Thread {
186170
}
187171
}
188172

189-
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
173+
fn sleep_with(nanos: u64, clock_id: wasi::Clockid, flags: u16) {
174+
const USERDATA: wasi::Userdata = 0x0123_45678;
175+
176+
let clock = wasi::SubscriptionClock { id: clock_id, timeout: nanos, precision: 0, flags };
177+
178+
let in_ = wasi::Subscription {
179+
userdata: USERDATA,
180+
u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
181+
};
182+
unsafe {
183+
let mut event: wasi::Event = mem::zeroed();
184+
let res = wasi::poll_oneoff(&in_, &mut event, 1);
185+
match (res, event) {
186+
(
187+
Ok(1),
188+
wasi::Event {
189+
userdata: USERDATA,
190+
error: wasi::ERRNO_SUCCESS,
191+
type_: wasi::EVENTTYPE_CLOCK,
192+
..
193+
},
194+
) => {}
195+
_ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
196+
}
197+
}
198+
}
199+
200+
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
190201
unsupported()
191202
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ impl Instant {
3636
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
3737
Some(Instant(self.0.checked_sub(*other)?))
3838
}
39+
40+
pub(crate) fn into_inner(self) -> Duration {
41+
self.0
42+
}
3943
}
4044

4145
impl SystemTime {

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ impl Thread {
105105
}
106106
}
107107

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

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
sleep(delay);
136+
}
137+
}
138+
131139
pub fn join(self) {
132140
join_thread(self.tid).unwrap();
133141
}

0 commit comments

Comments
 (0)