diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index ca9d3fd592bf..3ca84db0f47f 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1822,7 +1822,7 @@ impl File { _ => { #[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))] { - use crate::sys::{time::__timespec64, weak::weak}; + use crate::sys::pal::{time::__timespec64, weak::weak}; // Added in glibc 2.34 weak!( @@ -2258,7 +2258,7 @@ fn set_times_impl(p: &CStr, times: FileTimes, follow_symlinks: bool) -> io::Resu let flags = if follow_symlinks { 0 } else { libc::AT_SYMLINK_NOFOLLOW }; #[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))] { - use crate::sys::{time::__timespec64, weak::weak}; + use crate::sys::pal::{time::__timespec64, weak::weak}; // Added in glibc 2.34 weak!( diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 0021c013d3d9..fbea94ec84e7 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -1,11 +1,10 @@ use core::num::niche_types::Nanoseconds; -use crate::sys::AsInner; +use crate::io; use crate::time::Duration; -use crate::{fmt, io}; 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 pub const TIMESPEC_MAX: libc::timespec = libc::timespec { tv_sec: ::MAX, tv_nsec: 1_000_000_000 - 1 }; @@ -18,60 +17,19 @@ pub(in crate::sys) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec { tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64, }; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SystemTime { - pub(crate) t: Timespec, -} - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) struct Timespec { - tv_sec: i64, - tv_nsec: Nanoseconds, -} - -impl SystemTime { - pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; - - pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; - - #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))] - pub fn new(tv_sec: i64, tv_nsec: i64) -> Result { - Ok(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) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime { t: self.t.checked_add_duration(other)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime { t: self.t.checked_sub_duration(other)? }) - } -} - -impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SystemTime") - .field("tv_sec", &self.t.tv_sec) - .field("tv_nsec", &self.t.tv_nsec) - .finish() - } + pub tv_sec: i64, + pub tv_nsec: Nanoseconds, } impl Timespec { - const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) }; + pub const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) }; // As described below, on Apple OS, dates before epoch are represented differently. // This is not an issue here however, because we are using tv_sec = i64::MIN, // which will cause the compatibility wrapper to not be executed at all. - const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) }; + pub const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) }; const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec { Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } } @@ -81,7 +39,7 @@ impl Timespec { unsafe { Self::new_unchecked(0, 0) } } - const fn new(tv_sec: i64, tv_nsec: i64) -> Result { + pub const fn new(tv_sec: i64, tv_nsec: i64) -> Result { // On Apple OS, dates before epoch are represented differently than on other // Unix platforms: e.g. 1/10th of a second before epoch is represented as `seconds=-1` // and `nanoseconds=100_000_000` on other platforms, but is `seconds=0` and @@ -263,98 +221,3 @@ impl __timespec64 { Self { tv_sec, tv_nsec, _padding: 0 } } } - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Instant { - t: Timespec, -} - -impl Instant { - // 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. - // - // We use `CLOCK_UPTIME_RAW` instead of `CLOCK_MONOTONIC` since - // `CLOCK_UPTIME_RAW` is based on `mach_absolute_time`, which is the - // clock that all timeouts and deadlines are measured against inside - // the kernel. - #[cfg(target_vendor = "apple")] - pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW; - - #[cfg(not(target_vendor = "apple"))] - pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC; - - pub fn now() -> Instant { - // https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html - Instant { t: Timespec::now(Self::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)? }) - } - - #[cfg_attr( - not(target_os = "linux"), - allow(unused, reason = "needed by the `sleep_until` on some unix platforms") - )] - pub(crate) fn into_timespec(self) -> Timespec { - self.t - } - - /// Returns `self` converted into units of `mach_absolute_time`, or `None` - /// if `self` is before the system boot time. If the conversion cannot be - /// performed precisely, this ceils the result up to the nearest - /// representable value. - #[cfg(target_vendor = "apple")] - pub fn into_mach_absolute_time_ceil(self) -> Option { - #[repr(C)] - struct mach_timebase_info { - numer: u32, - denom: u32, - } - - unsafe extern "C" { - unsafe fn mach_timebase_info(info: *mut mach_timebase_info) -> libc::kern_return_t; - } - - let secs = u64::try_from(self.t.tv_sec).ok()?; - - let mut timebase = mach_timebase_info { numer: 0, denom: 0 }; - assert_eq!(unsafe { mach_timebase_info(&mut timebase) }, libc::KERN_SUCCESS); - - // Since `tv_sec` is 64-bit and `tv_nsec` is smaller than 1 billion, - // this cannot overflow. The resulting number needs at most 94 bits. - let nanos = - u128::from(secs) * u128::from(NSEC_PER_SEC) + u128::from(self.t.tv_nsec.as_inner()); - // This multiplication cannot overflow since multiplying a 94-bit - // number by a 32-bit number yields a number that needs at most - // 126 bits. - Some((nanos * u128::from(timebase.denom)).div_ceil(u128::from(timebase.numer))) - } -} - -impl AsInner for Instant { - fn as_inner(&self) -> &Timespec { - &self.t - } -} - -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) - .finish() - } -} diff --git a/library/std/src/sys/time/mod.rs b/library/std/src/sys/time/mod.rs index 810d16b19368..3efab78518c2 100644 --- a/library/std/src/sys/time/mod.rs +++ b/library/std/src/sys/time/mod.rs @@ -14,6 +14,10 @@ cfg_select! { mod uefi; use uefi as imp; } + target_family = "unix" => { + mod unix; + use unix as imp; + } target_os = "vexos" => { mod vexos; #[expect(unused)] diff --git a/library/std/src/sys/time/unix.rs b/library/std/src/sys/time/unix.rs new file mode 100644 index 000000000000..21d246bc850a --- /dev/null +++ b/library/std/src/sys/time/unix.rs @@ -0,0 +1,141 @@ +use crate::sys::AsInner; +use crate::sys::pal::time::Timespec; +use crate::time::Duration; +use crate::{fmt, io}; + +pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() }; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct SystemTime { + pub(crate) t: Timespec, +} + +impl SystemTime { + pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + + pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + + #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))] + pub fn new(tv_sec: i64, tv_nsec: i64) -> Result { + Ok(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) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(SystemTime { t: self.t.checked_add_duration(other)? }) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime { t: self.t.checked_sub_duration(other)? }) + } +} + +impl fmt::Debug for SystemTime { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SystemTime") + .field("tv_sec", &self.t.tv_sec) + .field("tv_nsec", &self.t.tv_nsec) + .finish() + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Instant { + t: Timespec, +} + +impl Instant { + // 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. + // + // We use `CLOCK_UPTIME_RAW` instead of `CLOCK_MONOTONIC` since + // `CLOCK_UPTIME_RAW` is based on `mach_absolute_time`, which is the + // clock that all timeouts and deadlines are measured against inside + // the kernel. + #[cfg(target_vendor = "apple")] + pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW; + + #[cfg(not(target_vendor = "apple"))] + pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC; + + pub fn now() -> Instant { + // https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html + Instant { t: Timespec::now(Self::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)? }) + } + + #[cfg_attr( + not(target_os = "linux"), + allow(unused, reason = "needed by the `sleep_until` on some unix platforms") + )] + pub(crate) fn into_timespec(self) -> Timespec { + self.t + } + + /// Returns `self` converted into units of `mach_absolute_time`, or `None` + /// if `self` is before the system boot time. If the conversion cannot be + /// performed precisely, this ceils the result up to the nearest + /// representable value. + #[cfg(target_vendor = "apple")] + pub fn into_mach_absolute_time_ceil(self) -> Option { + #[repr(C)] + struct mach_timebase_info { + numer: u32, + denom: u32, + } + + unsafe extern "C" { + unsafe fn mach_timebase_info(info: *mut mach_timebase_info) -> libc::kern_return_t; + } + + let secs = u64::try_from(self.t.tv_sec).ok()?; + + let mut timebase = mach_timebase_info { numer: 0, denom: 0 }; + assert_eq!(unsafe { mach_timebase_info(&mut timebase) }, libc::KERN_SUCCESS); + + // Since `tv_sec` is 64-bit and `tv_nsec` is smaller than 1 billion, + // this cannot overflow. The resulting number needs at most 94 bits. + let nanos = 1_000_000_000 * u128::from(secs) + u128::from(self.t.tv_nsec.as_inner()); + // This multiplication cannot overflow since multiplying a 94-bit + // number by a 32-bit number yields a number that needs at most + // 126 bits. + Some((nanos * u128::from(timebase.denom)).div_ceil(u128::from(timebase.numer))) + } +} + +impl AsInner for Instant { + fn as_inner(&self) -> &Timespec { + &self.t + } +} + +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) + .finish() + } +}