From f264d28f2cb941500d89e97a053ae96322c8ed86 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 28 Sep 2023 12:11:20 -0400 Subject: [PATCH 1/3] time: cfg(any(x)) is the same as cfg(x) This was left over in c043a0e7d6f347f9b2c7f08c5b3a179470e0f0c5. --- library/std/src/sys/unix/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 4fe61b28488b4..c94a29b510a04 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -217,7 +217,7 @@ impl From<__timespec64> for Timespec { } #[cfg(any( - all(target_os = "macos", any(not(target_arch = "aarch64"))), + all(target_os = "macos", not(target_arch = "aarch64")), target_os = "ios", target_os = "watchos", target_os = "tvos" @@ -338,7 +338,7 @@ mod inner { } #[cfg(not(any( - all(target_os = "macos", any(not(target_arch = "aarch64"))), + all(target_os = "macos", not(target_arch = "aarch64")), target_os = "ios", target_os = "watchos", target_os = "tvos" From b21eb4f046284040b8e91aff0fd1e7c5125864d1 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 28 Sep 2023 12:27:24 -0400 Subject: [PATCH 2/3] time: use clock_gettime on macos Replace `gettimeofday` with `clock_gettime(CLOCK_REALTIME)` on: ``` all(target_os = "macos", not(target_arch = "aarch64")), target_os = "ios", target_os = "watchos", target_os = "tvos" ))] ``` `gettimeofday` was first used in https://github.com/time-rs/time/commit/cc367edd953e72756ed6f0980918795c11e469b1 which predated the introduction of `clock_gettime` support in macOS 10.12 Sierra which became the minimum supported version in 58bbca958d917a89124da248735926f86c59a149. --- library/std/src/sys/unix/time.rs | 84 +++++++++++++------------------- library/std/src/time.rs | 3 +- 2 files changed, 36 insertions(+), 51 deletions(-) diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index c94a29b510a04..3ad6e5d5d482d 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -40,6 +40,10 @@ impl SystemTime { SystemTime { t: Timespec::new(tv_sec, tv_nsec) } } + pub fn now() -> SystemTime { + SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) } + } + pub fn sub_time(&self, other: &SystemTime) -> Result { self.t.sub_timespec(&other.t) } @@ -79,6 +83,36 @@ impl Timespec { Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } } } + pub fn now(clock: libc::clockid_t) -> Timespec { + use crate::mem::MaybeUninit; + use crate::sys::cvt; + + // Try to use 64-bit time in preparation for Y2038. + #[cfg(all( + target_os = "linux", + target_env = "gnu", + target_pointer_width = "32", + not(target_arch = "riscv32") + ))] + { + use crate::sys::weak::weak; + + // __clock_gettime64 was added to 32-bit arches in glibc 2.34, + // and it handles both vDSO calls and ENOSYS fallbacks itself. + weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int); + + if let Some(clock_gettime64) = __clock_gettime64.get() { + let mut t = MaybeUninit::uninit(); + cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap(); + return Timespec::from(unsafe { t.assume_init() }); + } + } + + let mut t = MaybeUninit::uninit(); + cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap(); + Timespec::from(unsafe { t.assume_init() }) + } + pub fn sub_timespec(&self, other: &Timespec) -> Result { if self >= other { // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM @@ -224,7 +258,6 @@ impl From<__timespec64> for Timespec { ))] mod inner { use crate::sync::atomic::{AtomicU64, Ordering}; - use crate::sys::cvt; use crate::sys_common::mul_div_u64; use crate::time::Duration; @@ -268,16 +301,6 @@ mod inner { } } - impl SystemTime { - pub fn now() -> SystemTime { - use crate::ptr; - - let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 }; - cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap(); - return SystemTime::from(s); - } - } - impl From for Timespec { fn from(t: libc::timeval) -> Timespec { Timespec::new(t.tv_sec as i64, 1000 * t.tv_usec as i64) @@ -345,11 +368,9 @@ mod inner { )))] mod inner { use crate::fmt; - use crate::mem::MaybeUninit; - use crate::sys::cvt; use crate::time::Duration; - use super::{SystemTime, Timespec}; + use super::Timespec; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Instant { @@ -386,39 +407,4 @@ mod inner { .finish() } } - - impl SystemTime { - pub fn now() -> SystemTime { - SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) } - } - } - - impl Timespec { - pub fn now(clock: libc::clockid_t) -> Timespec { - // Try to use 64-bit time in preparation for Y2038. - #[cfg(all( - target_os = "linux", - target_env = "gnu", - target_pointer_width = "32", - not(target_arch = "riscv32") - ))] - { - use crate::sys::weak::weak; - - // __clock_gettime64 was added to 32-bit arches in glibc 2.34, - // and it handles both vDSO calls and ENOSYS fallbacks itself. - weak!(fn __clock_gettime64(libc::clockid_t, *mut super::__timespec64) -> libc::c_int); - - if let Some(clock_gettime64) = __clock_gettime64.get() { - let mut t = MaybeUninit::uninit(); - cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap(); - return Timespec::from(unsafe { t.assume_init() }); - } - } - - let mut t = MaybeUninit::uninit(); - cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap(); - Timespec::from(unsafe { t.assume_init() }) - } - } } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index c638cc61856fa..ddac069df760b 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -221,7 +221,7 @@ pub struct Instant(time::Instant); /// |-----------|----------------------------------------------------------------------| /// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | /// | UNIX | [clock_gettime (Realtime Clock)] | -/// | Darwin | [gettimeofday] | +/// | Darwin | [clock_gettime (Realtime Clock)] | /// | VXWorks | [clock_gettime (Realtime Clock)] | /// | SOLID | `SOLID_RTC_ReadTime` | /// | WASI | [__wasi_clock_time_get (Realtime Clock)] | @@ -230,7 +230,6 @@ pub struct Instant(time::Instant); /// [currently]: crate::io#platform-specific-behavior /// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time /// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode -/// [gettimeofday]: https://man7.org/linux/man-pages/man2/gettimeofday.2.html /// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime /// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get /// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime From bc300102d4388860afa895149c1f52393a7aa964 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 28 Sep 2023 17:34:41 -0400 Subject: [PATCH 3/3] time: use clock_gettime on macos Replace `mach_{absolute_time,timebase_info}` with `clock_gettime(CLOCK_REALTIME)` on: ``` all(target_os = "macos", not(target_arch = "aarch64")), target_os = "ios", target_os = "watchos", target_os = "tvos" ))] ``` `mach_{absolute_time,timebase_info}` were first used in https://github.com/time-rs/time/commit/cc367edd953e72756ed6f0980918795c11e469b1 which predated the introduction of `clock_gettime` support in macOS 10.12 Sierra which became the minimum supported version in 58bbca958d917a89124da248735926f86c59a149. Note that this change was made for aarch64 in 5008a317ce8e508c390ed12bff281f307313376e which predated 10.12 becoming the minimum supported version. The discussion took place in https://github.com/rust-lang/rust/issues/91417 and in particular https://github.com/rust-lang/rust/issues/91417#issuecomment-992151582 and https://github.com/rust-lang/rust/issues/91417#issuecomment-1033048064 are relevant. --- library/std/src/sys/unix/time.rs | 192 +++++++------------------------ library/std/src/time.rs | 3 +- 2 files changed, 45 insertions(+), 150 deletions(-) diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 3ad6e5d5d482d..e4540b99413bf 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -1,8 +1,6 @@ use crate::fmt; use crate::time::Duration; -pub use self::inner::Instant; - const NSEC_PER_SEC: u64 = 1_000_000_000; pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() }; #[allow(dead_code)] // Used for pthread condvar timeouts @@ -250,161 +248,59 @@ impl From<__timespec64> for Timespec { } } -#[cfg(any( - all(target_os = "macos", not(target_arch = "aarch64")), - target_os = "ios", - target_os = "watchos", - target_os = "tvos" -))] -mod inner { - use crate::sync::atomic::{AtomicU64, Ordering}; - use crate::sys_common::mul_div_u64; - use crate::time::Duration; - - use super::{SystemTime, Timespec, NSEC_PER_SEC}; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] - pub struct Instant { - t: u64, - } - - #[repr(C)] - #[derive(Copy, Clone)] - struct mach_timebase_info { - numer: u32, - denom: u32, - } - type mach_timebase_info_t = *mut mach_timebase_info; - type kern_return_t = libc::c_int; - - impl Instant { - pub fn now() -> Instant { - extern "C" { - fn mach_absolute_time() -> u64; - } - Instant { t: unsafe { mach_absolute_time() } } - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - let diff = self.t.checked_sub(other.t)?; - let info = info(); - let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64); - Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? }) - } - } - - impl From for Timespec { - fn from(t: libc::timeval) -> Timespec { - Timespec::new(t.tv_sec as i64, 1000 * t.tv_usec as i64) - } - } - - impl From for SystemTime { - fn from(t: libc::timeval) -> SystemTime { - SystemTime { t: Timespec::from(t) } - } - } - - fn checked_dur2intervals(dur: &Duration) -> Option { - let nanos = - dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?; - let info = info(); - Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64)) - } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Instant { + t: Timespec, +} - fn info() -> mach_timebase_info { - // INFO_BITS conceptually is an `Option`. We can do - // this in 64 bits because we know 0 is never a valid value for the - // `denom` field. +impl Instant { + pub fn now() -> Instant { + // https://www.manpagez.com/man/3/clock_gettime/ // - // Encoding 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 INFO_BITS: AtomicU64 = AtomicU64::new(0); - - // If a previous thread has initialized `INFO_BITS`, use it. - let info_bits = INFO_BITS.load(Ordering::Relaxed); - if info_bits != 0 { - return info_from_bits(info_bits); - } - - // ... otherwise learn for ourselves ... - extern "C" { - fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t; - } - - let mut info = info_from_bits(0); - unsafe { - mach_timebase_info(&mut info); - } - INFO_BITS.store(info_to_bits(info), Ordering::Relaxed); - info + // CLOCK_UPTIME_RAW clock that increments monotonically, in the same man- + // ner as CLOCK_MONOTONIC_RAW, but that does not incre- + // ment while the system is asleep. The returned value + // is identical to the result of mach_absolute_time() + // after the appropriate mach_timebase conversion is + // applied. + // + // Instant on macos was historically implemented using mach_absolute_time; + // we preserve this value domain out of an abundance of caution. + #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos" + ))] + const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW; + #[cfg(not(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos" + )))] + const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC; + Instant { t: Timespec::now(clock_id) } } - #[inline] - fn info_to_bits(info: mach_timebase_info) -> u64 { - ((info.denom as u64) << 32) | (info.numer as u64) + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.t.sub_timespec(&other.t).ok() } - #[inline] - fn info_from_bits(bits: u64) -> mach_timebase_info { - mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant { t: self.t.checked_add_duration(other)? }) } -} -#[cfg(not(any( - all(target_os = "macos", not(target_arch = "aarch64")), - target_os = "ios", - target_os = "watchos", - target_os = "tvos" -)))] -mod inner { - use crate::fmt; - use crate::time::Duration; - - use super::Timespec; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct Instant { - t: Timespec, - } - - impl Instant { - pub fn now() -> Instant { - #[cfg(target_os = "macos")] - const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW; - #[cfg(not(target_os = "macos"))] - const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC; - Instant { t: Timespec::now(clock_id) } - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option { - self.t.sub_timespec(&other.t).ok() - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_add_duration(other)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(Instant { t: self.t.checked_sub_duration(other)? }) - } + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant { t: self.t.checked_sub_duration(other)? }) } +} - impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Instant") - .field("tv_sec", &self.t.tv_sec) - .field("tv_nsec", &self.t.tv_nsec.0) - .finish() - } +impl fmt::Debug for Instant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Instant") + .field("tv_sec", &self.t.tv_sec) + .field("tv_nsec", &self.t.tv_nsec.0) + .finish() } } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index ddac069df760b..04229ec6c5483 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -109,7 +109,7 @@ pub use core::time::TryFromFloatSecsError; /// |-----------|----------------------------------------------------------------------| /// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | /// | UNIX | [clock_gettime (Monotonic Clock)] | -/// | Darwin | [mach_absolute_time] | +/// | Darwin | [clock_gettime (Monotonic Clock)] | /// | VXWorks | [clock_gettime (Monotonic Clock)] | /// | SOLID | `get_tim` | /// | WASI | [__wasi_clock_time_get (Monotonic Clock)] | @@ -121,7 +121,6 @@ pub use core::time::TryFromFloatSecsError; /// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode /// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get /// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime -/// [mach_absolute_time]: https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/services/services.html /// /// **Disclaimer:** These system calls might change over time. ///