From f4623121581602a36eb376c012be6d819ff8ae50 Mon Sep 17 00:00:00 2001 From: joboet Date: Fri, 26 Sep 2025 17:04:51 +0200 Subject: [PATCH] std: respect the bounds of the platform's data structures when performing time arithmetic --- library/std/src/sys/fs/wasi.rs | 12 +- .../std/src/sys/pal/sgx/abi/usercalls/mod.rs | 5 +- library/std/src/sys/pal/sgx/time.rs | 38 ++-- library/std/src/sys/pal/unsupported/time.rs | 15 +- library/std/src/sys/pal/vexos/time.rs | 17 +- library/std/src/sys/pal/wasip1/time.rs | 51 ++++-- library/std/src/sys/pal/wasip2/time.rs | 32 ++-- library/std/src/sys/pal/windows/time.rs | 169 +++++++++--------- library/std/src/sys/pal/xous/time.rs | 38 ++-- library/std/src/sys/thread/wasip2.rs | 19 +- 10 files changed, 220 insertions(+), 176 deletions(-) diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs index 0b65b9cb389df..9cec35212668e 100644 --- a/library/std/src/sys/fs/wasi.rs +++ b/library/std/src/sys/fs/wasi.rs @@ -536,17 +536,9 @@ impl File { } pub fn set_times(&self, times: FileTimes) -> io::Result<()> { - let to_timestamp = |time: Option| match time { - Some(time) if let Some(ts) = time.to_wasi_timestamp() => Ok(ts), - Some(_) => Err(io::const_error!( - io::ErrorKind::InvalidInput, - "timestamp is too large to set as a file time", - )), - None => Ok(0), - }; self.fd.filestat_set_times( - to_timestamp(times.accessed)?, - to_timestamp(times.modified)?, + times.accessed.map_or(0, SystemTime::to_wasi_timestamp), + times.modified.map_or(0, SystemTime::to_wasi_timestamp), times.accessed.map_or(0, |_| wasi::FSTFLAGS_ATIM) | times.modified.map_or(0, |_| wasi::FSTFLAGS_MTIM), ) diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs index 5041770faf661..49e34e20c2720 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -266,9 +266,8 @@ pub fn send(event_set: u64, tcs: Option) -> IoResult<()> { /// Usercall `insecure_time`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] -pub fn insecure_time() -> Duration { - let t = unsafe { raw::insecure_time().0 }; - Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _) +pub fn insecure_time() -> u64 { + unsafe { raw::insecure_time().0 } } /// Usercall `alloc`. See the ABI documentation for more information. diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs index db4cf2804bf13..e86c4bafa5d58 100644 --- a/library/std/src/sys/pal/sgx/time.rs +++ b/library/std/src/sys/pal/sgx/time.rs @@ -2,45 +2,61 @@ use super::abi::usercalls; use crate::time::Duration; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); +pub struct Instant { + nanos: u64, +} #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime(Duration); +pub struct SystemTime { + nanos: u64, +} -pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); +pub const UNIX_EPOCH: SystemTime = SystemTime { nanos: 0 }; impl Instant { pub fn now() -> Instant { - Instant(usercalls::insecure_time()) + Instant { nanos: usercalls::insecure_time() } } pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) + let nanos = self.nanos.checked_sub(other.nanos)?; + Some(Duration::from_nanos(nanos)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_add(*other)?)) + let to_add = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_add(to_add)?; + Some(Instant { nanos }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_sub(*other)?)) + let to_sub = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_sub(to_sub)?; + Some(Instant { nanos }) } } impl SystemTime { pub fn now() -> SystemTime { - SystemTime(usercalls::insecure_time()) + SystemTime { nanos: usercalls::insecure_time() } } pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + self.nanos + .checked_sub(other.nanos) + .map(Duration::from_nanos) + .ok_or_else(|| Duration::from_nanos(other.nanos - self.nanos)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_add(*other)?)) + let to_add = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_add(to_add)?; + Some(SystemTime { nanos }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_sub(*other)?)) + let to_sub = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_sub(to_sub)?; + Some(SystemTime { nanos }) } } diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs index 6d67b538a96bf..f6a43db659e15 100644 --- a/library/std/src/sys/pal/unsupported/time.rs +++ b/library/std/src/sys/pal/unsupported/time.rs @@ -1,7 +1,8 @@ use crate::time::Duration; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); +#[allow(unreachable_code)] // Generated by the PartialEq derive. +pub struct Instant(!); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct SystemTime(Duration); @@ -13,16 +14,16 @@ impl Instant { panic!("time not implemented on this platform") } - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) + pub fn checked_sub_instant(&self, _other: &Instant) -> Option { + self.0 } - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_add(*other)?)) + pub fn checked_add_duration(&self, _other: &Duration) -> Option { + self.0 } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_sub(*other)?)) + pub fn checked_sub_duration(&self, _other: &Duration) -> Option { + self.0 } } diff --git a/library/std/src/sys/pal/vexos/time.rs b/library/std/src/sys/pal/vexos/time.rs index f95d96cd27ac0..28382e3edbbdf 100644 --- a/library/std/src/sys/pal/vexos/time.rs +++ b/library/std/src/sys/pal/vexos/time.rs @@ -6,23 +6,30 @@ mod unsupported_time; pub use unsupported_time::{SystemTime, UNIX_EPOCH}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); +pub struct Instant { + micros: u64, +} impl Instant { pub fn now() -> Instant { let micros = unsafe { vex_sdk::vexSystemHighResTimeGet() }; - Self(Duration::from_micros(micros)) + Self { micros } } pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) + let micros = self.micros.checked_sub(other.micros)?; + Some(Duration::from_micros(micros)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_add(*other)?)) + let to_add = other.as_micros().try_into().ok()?; + let micros = self.micros.checked_add(to_add)?; + Some(Instant { micros }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_sub(*other)?)) + let to_sub = other.as_micros().try_into().ok()?; + let micros = self.micros.checked_sub(to_sub)?; + Some(Instant { micros }) } } diff --git a/library/std/src/sys/pal/wasip1/time.rs b/library/std/src/sys/pal/wasip1/time.rs index 0d8d0b59ac14a..13b63a4d9e673 100644 --- a/library/std/src/sys/pal/wasip1/time.rs +++ b/library/std/src/sys/pal/wasip1/time.rs @@ -3,63 +3,78 @@ use crate::time::Duration; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); +pub struct Instant { + nanos: wasi::Timestamp, +} #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime(Duration); +pub struct SystemTime { + nanos: wasi::Timestamp, +} -pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); +pub const UNIX_EPOCH: SystemTime = SystemTime { nanos: 0 }; -fn current_time(clock: wasi::Clockid) -> Duration { - let ts = unsafe { +fn current_time(clock: wasi::Clockid) -> wasi::Timestamp { + unsafe { wasi::clock_time_get( clock, 1, // precision... seems ignored though? ) .unwrap() - }; - Duration::new((ts / 1_000_000_000) as u64, (ts % 1_000_000_000) as u32) + } } impl Instant { pub fn now() -> Instant { - Instant(current_time(wasi::CLOCKID_MONOTONIC)) + Instant { nanos: current_time(wasi::CLOCKID_MONOTONIC) } } pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) + let nanos = self.nanos.checked_sub(other.nanos)?; + Some(Duration::from_nanos(nanos)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_add(*other)?)) + let to_add = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_add(to_add)?; + Some(Instant { nanos }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_sub(*other)?)) + let to_sub = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_sub(to_sub)?; + Some(Instant { nanos }) } } impl SystemTime { pub fn now() -> SystemTime { - SystemTime(current_time(wasi::CLOCKID_REALTIME)) + SystemTime { nanos: current_time(wasi::CLOCKID_REALTIME) } } pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { - SystemTime(Duration::from_nanos(ts)) + SystemTime { nanos: ts } } - pub fn to_wasi_timestamp(&self) -> Option { - self.0.as_nanos().try_into().ok() + pub fn to_wasi_timestamp(self) -> wasi::Timestamp { + self.nanos } pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + self.nanos + .checked_sub(other.nanos) + .map(Duration::from_nanos) + .ok_or_else(|| Duration::from_nanos(other.nanos - self.nanos)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_add(*other)?)) + let to_add = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_add(to_add)?; + Some(SystemTime { nanos }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_sub(*other)?)) + let to_sub = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_sub(to_sub)?; + Some(SystemTime { nanos }) } } diff --git a/library/std/src/sys/pal/wasip2/time.rs b/library/std/src/sys/pal/wasip2/time.rs index 434891839944d..6953f01477169 100644 --- a/library/std/src/sys/pal/wasip2/time.rs +++ b/library/std/src/sys/pal/wasip2/time.rs @@ -1,8 +1,12 @@ use crate::time::Duration; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); +pub struct Instant { + nanos: wasip2::clocks::monotonic_clock::Instant, +} +// WASIp2's datetime is identical to our `Duration` in terms of its representable +// range, so use `Duration` to simplify the implementation below. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct SystemTime(Duration); @@ -10,23 +14,28 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); impl Instant { pub fn now() -> Instant { - Instant(Duration::from_nanos(wasip2::clocks::monotonic_clock::now())) + Instant { nanos: wasip2::clocks::monotonic_clock::now() } + } + + pub fn to_wasi_instant(self) -> wasip2::clocks::monotonic_clock::Instant { + self.nanos } pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) + let nanos = self.nanos.checked_sub(other.nanos)?; + Some(Duration::from_nanos(nanos)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_add(*other)?)) + let to_add = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_add(to_add)?; + Some(Instant { nanos }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant(self.0.checked_sub(*other)?)) - } - - pub(crate) fn as_duration(&self) -> &Duration { - &self.0 + let to_sub = other.as_nanos().try_into().ok()?; + let nanos = self.nanos.checked_sub(to_sub)?; + Some(Instant { nanos }) } } @@ -40,8 +49,9 @@ impl SystemTime { SystemTime(Duration::from_nanos(ts)) } - pub fn to_wasi_timestamp(&self) -> Option { - self.0.as_nanos().try_into().ok() + pub fn to_wasi_timestamp(self) -> wasi::Timestamp { + // FIXME: use the WASIp2 filesystem proposal, which accepts a WASIp2 datetime. + self.0.as_nanos().try_into().expect("error converting WASIp2 datetime to WASIp1 timestamp") } pub fn sub_time(&self, other: &SystemTime) -> Result { diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 0d31b80e56afc..c99c87de7ee8a 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -1,9 +1,11 @@ -use core::hash::{Hash, Hasher}; -use core::ops::Neg; - use crate::cmp::Ordering; +use crate::hash::{Hash, Hasher}; +use crate::num::NonZero; +use crate::ops::Neg; use crate::ptr::null; -use crate::sys::c; +use crate::sync::atomic::Ordering::Relaxed; +use crate::sync::atomic::{Atomic, AtomicU64}; +use crate::sys::pal::{c, cvt}; use crate::sys_common::IntoInner; use crate::time::Duration; use crate::{fmt, mem}; @@ -13,9 +15,10 @@ const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100; #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] pub struct Instant { - // This duration is relative to an arbitrary microsecond epoch - // from the winapi QueryPerformanceCounter function. - t: Duration, + // High precision timing on windows operates in "Performance Counter" + // units, as returned by the WINAPI QueryPerformanceCounter function. + // These relate to seconds by a factor of QueryPerformanceFrequency. + ticks: i64, } #[derive(Copy, Clone)] @@ -34,32 +37,93 @@ pub const UNIX_EPOCH: SystemTime = SystemTime { impl Instant { pub fn now() -> Instant { - // High precision timing on windows operates in "Performance Counter" - // units, as returned by the WINAPI QueryPerformanceCounter function. - // These relate to seconds by a factor of QueryPerformanceFrequency. - // In order to keep unit conversions out of normal interval math, we - // measure in QPC units and immediately convert to nanoseconds. - perf_counter::PerformanceCounterInstant::now().into() + let mut ticks: i64 = 0; + cvt(unsafe { c::QueryPerformanceCounter(&mut ticks) }).unwrap(); + Instant { ticks } + } + + fn frequency() -> NonZero { + // Either the cached result of `QueryPerformanceFrequency` or `0` for + // uninitialized. Storing this as a single `AtomicU64` allows us to use + // `Relaxed` operations, as we are only interested in the effects on a + // single memory location. + static FREQUENCY: Atomic = AtomicU64::new(0); + + let cached = FREQUENCY.load(Relaxed); + // If a previous thread has filled in this global state, use that. + if let Some(cached) = NonZero::new(cached) { + return cached; + } + + // ... otherwise learn for ourselves ... + let mut frequency = 0; + unsafe { + cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap(); + } + + let frequency = NonZero::new(frequency.cast_unsigned()) + .expect("frequency of performance counter should not be zero"); + + // Check that the frequency can be safely multiplied with `NANOS_PER_SECOND`. + // This should always succeed since the performance counter is documented not + // to wrap around for 100 years, so the maximum frequency is less than 6 billion + // ticks per second, which in turn means that this multiplication will not overflow. + frequency + .get() + .checked_mul(NANOS_PER_SEC) + .expect("wraparound must only occur after 100 years"); + + FREQUENCY.store(frequency.get(), Relaxed); + frequency } pub fn checked_sub_instant(&self, other: &Instant) -> Option { - // On windows there's a threshold below which we consider two timestamps - // equivalent due to measurement error. For more details + doc link, - // check the docs on epsilon. - let epsilon = perf_counter::PerformanceCounterInstant::epsilon(); - if other.t > self.t && other.t - self.t <= epsilon { - Some(Duration::new(0, 0)) + if self.ticks >= other.ticks { + // Find the difference by performing an unsigned subtraction, as + // the subtraction might overflow otherwise. + let ticks = self.ticks.cast_unsigned().wrapping_sub(other.ticks.cast_unsigned()); + let freq = Self::frequency(); + let secs = ticks / freq; + let subsec_ticks = ticks % freq; + // SAFETY: + // `subsec_ticks` is smaller than `freq`, and `freq` can be multiplied + // with `NANOS_PER_SEC` without overflow (we checked that in the + // `frequency` function above). + let subsec_nanos = unsafe { NANOS_PER_SEC.unchecked_mul(subsec_ticks) / freq }; + Some(Duration::new(secs, subsec_nanos as u32)) + } else if other.ticks == self.ticks + 1 { + // Per microsoft docs, the margin of error for cross-thread time + // comparisons using QueryPerformanceCounter is one tick, hence we + // consider `other` to be equal to `self` if the difference is only + // one tick. + // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo/acquiring-high-resolution-time-stamps + Some(Duration::ZERO) } else { - self.t.checked_sub(other.t) + None } } + fn duration2ticks(dur: Duration) -> Option { + let freq = Self::frequency(); + let whole = dur.as_secs().checked_mul(freq.get())?; + // SAFETY: + // `subsec_nanos` is smaller than `NANOS_PER_SEC` and `freq` can be + // multiplied with `NANOS_PER_SEC` without overflow (we checked that in the + // `frequency` function above). + let frac = unsafe { freq.get().unchecked_mul(dur.subsec_nanos().into()) } / NANOS_PER_SEC; + whole.checked_add(frac) + } + pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_add(*other)? }) + let to_add = Self::duration2ticks(*other)?; + let ticks = self.ticks.checked_add_unsigned(to_add)?; + Some(Instant { ticks }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_sub(*other)? }) + let to_sub = Self::duration2ticks(*other)?; + let ticks = self.ticks.checked_sub_unsigned(to_sub)?; + Some(Instant { ticks }) } } @@ -162,67 +226,6 @@ fn intervals2dur(intervals: u64) -> Duration { Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32) } -mod perf_counter { - use super::NANOS_PER_SEC; - use crate::sync::atomic::{Atomic, AtomicU64, Ordering}; - use crate::sys::{c, cvt}; - use crate::sys_common::mul_div_u64; - use crate::time::Duration; - - pub struct PerformanceCounterInstant { - ts: i64, - } - impl PerformanceCounterInstant { - pub fn now() -> Self { - Self { ts: query() } - } - - // Per microsoft docs, the margin of error for cross-thread time comparisons - // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency(). - // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo - // /acquiring-high-resolution-time-stamps - pub fn epsilon() -> Duration { - let epsilon = NANOS_PER_SEC / (frequency() as u64); - Duration::from_nanos(epsilon) - } - } - impl From for super::Instant { - fn from(other: PerformanceCounterInstant) -> Self { - let freq = frequency() as u64; - let instant_nsec = mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq); - Self { t: Duration::from_nanos(instant_nsec) } - } - } - - fn frequency() -> i64 { - // Either the cached result of `QueryPerformanceFrequency` or `0` for - // uninitialized. Storing this as a single `AtomicU64` allows us to use - // `Relaxed` operations, as we are only interested in the effects on a - // single memory location. - static FREQUENCY: Atomic = AtomicU64::new(0); - - let cached = FREQUENCY.load(Ordering::Relaxed); - // If a previous thread has filled in this global state, use that. - if cached != 0 { - return cached as i64; - } - // ... otherwise learn for ourselves ... - let mut frequency = 0; - unsafe { - cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap(); - } - - FREQUENCY.store(frequency as u64, Ordering::Relaxed); - frequency - } - - fn query() -> i64 { - let mut qpc_value: i64 = 0; - cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap(); - qpc_value - } -} - /// A timer you can wait on. pub(crate) struct WaitableTimer { handle: c::HANDLE, diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs index ae8be81c0b7c5..d504b3de94bf3 100644 --- a/library/std/src/sys/pal/xous/time.rs +++ b/library/std/src/sys/pal/xous/time.rs @@ -5,12 +5,16 @@ use crate::os::xous::services::{systime_server, ticktimer_server}; use crate::time::Duration; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant(Duration); +pub struct Instant { + millis: u64, +} #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct SystemTime(Duration); +pub struct SystemTime { + millis: u64, +} -pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); +pub const UNIX_EPOCH: SystemTime = SystemTime { millis: 0 }; impl Instant { pub fn now() -> Instant { @@ -18,19 +22,24 @@ impl Instant { .expect("failed to request elapsed_ms"); let lower = result[0]; let upper = result[1]; - Instant { 0: Duration::from_millis(lower as u64 | (upper as u64) << 32) } + Instant { millis: lower as u64 | (upper as u64) << 32 } } pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.0.checked_sub(other.0) + let millis = self.millis.checked_sub(other.millis)?; + Some(Duration::from_millis(millis)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { - self.0.checked_add(*other).map(Instant) + let to_add = other.as_millis().try_into().ok()?; + let millis = self.millis.checked_add(to_add)?; + Some(Instant { millis }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - self.0.checked_sub(*other).map(Instant) + let to_sub = other.as_millis().try_into().ok()?; + let millis = self.millis.checked_sub(to_sub)?; + Some(Instant { millis }) } } @@ -40,18 +49,25 @@ impl SystemTime { .expect("failed to request utc time in ms"); let lower = result[0]; let upper = result[1]; - SystemTime { 0: Duration::from_millis((upper as u64) << 32 | lower as u64) } + SystemTime { millis: (upper as u64) << 32 | lower as u64 } } pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + self.millis + .checked_sub(other.millis) + .map(Duration::from_millis) + .ok_or_else(|| Duration::from_millis(other.millis - self.millis)) } pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_add(*other)?)) + let to_add = other.as_millis().try_into().ok()?; + let millis = self.millis.checked_add(to_add)?; + Some(SystemTime { millis }) } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_sub(*other)?)) + let to_sub = other.as_millis().try_into().ok()?; + let millis = self.millis.checked_sub(to_sub)?; + Some(SystemTime { millis }) } } diff --git a/library/std/src/sys/thread/wasip2.rs b/library/std/src/sys/thread/wasip2.rs index 420cad2a5e4ab..29ae85e2b9dd6 100644 --- a/library/std/src/sys/thread/wasip2.rs +++ b/library/std/src/sys/thread/wasip2.rs @@ -12,21 +12,6 @@ pub fn sleep(dur: Duration) { } pub fn sleep_until(deadline: Instant) { - match u64::try_from(deadline.into_inner().as_duration().as_nanos()) { - // If the point in time we're sleeping to fits within a 64-bit - // number of nanoseconds then directly use `subscribe_instant`. - Ok(deadline) => { - wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block(); - } - // ... otherwise we're sleeping for 500+ years relative to the - // "start" of what the system is using as a clock so speed/accuracy - // is not so much of a concern. Use `sleep` instead. - Err(_) => { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - sleep(delay); - } - } - } + wasip2::clocks::monotonic_clock::subscribe_instant(deadline.into_inner().to_wasi_instant()) + .block(); }