about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/std/src/sys/unix/time.rs274
-rw-r--r--library/std/src/time.rs6
2 files changed, 80 insertions, 200 deletions
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index 4fe61b28488..e4540b99413 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
@@ -40,6 +38,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<Duration, Duration> {
         self.t.sub_timespec(&other.t)
     }
@@ -79,6 +81,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<Duration, Duration> {
         if self >= other {
             // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
@@ -216,209 +248,59 @@ impl From<__timespec64> for Timespec {
     }
 }
 
-#[cfg(any(
-    all(target_os = "macos", any(not(target_arch = "aarch64"))),
-    target_os = "ios",
-    target_os = "watchos",
-    target_os = "tvos"
-))]
-mod inner {
-    use crate::sync::atomic::{AtomicU64, Ordering};
-    use crate::sys::cvt;
-    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<Duration> {
-            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<Instant> {
-            Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
-        }
-
-        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
-            Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
-        }
-    }
-
-    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<libc::timeval> for Timespec {
-        fn from(t: libc::timeval) -> Timespec {
-            Timespec::new(t.tv_sec as i64, 1000 * t.tv_usec as i64)
-        }
-    }
-
-    impl From<libc::timeval> for SystemTime {
-        fn from(t: libc::timeval) -> SystemTime {
-            SystemTime { t: Timespec::from(t) }
-        }
-    }
-
-    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
-        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))
-    }
-
-    fn info() -> mach_timebase_info {
-        // INFO_BITS conceptually is an `Option<mach_timebase_info>`. We can do
-        // this in 64 bits because we know 0 is never a valid value for the
-        // `denom` field.
-        //
-        // 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
-    }
-
-    #[inline]
-    fn info_to_bits(info: mach_timebase_info) -> u64 {
-        ((info.denom as u64) << 32) | (info.numer as u64)
-    }
-
-    #[inline]
-    fn info_from_bits(bits: u64) -> mach_timebase_info {
-        mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
-    }
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Instant {
+    t: Timespec,
 }
 
-#[cfg(not(any(
-    all(target_os = "macos", any(not(target_arch = "aarch64"))),
-    target_os = "ios",
-    target_os = "watchos",
-    target_os = "tvos"
-)))]
-mod inner {
-    use crate::fmt;
-    use crate::mem::MaybeUninit;
-    use crate::sys::cvt;
-    use crate::time::Duration;
-
-    use super::{SystemTime, Timespec};
-
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub struct Instant {
-        t: Timespec,
+impl Instant {
+    pub fn now() -> Instant {
+        // https://www.manpagez.com/man/3/clock_gettime/
+        //
+        // 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) }
     }
 
-    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<Duration> {
-            self.t.sub_timespec(&other.t).ok()
-        }
-
-        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
-            Some(Instant { t: self.t.checked_add_duration(other)? })
-        }
-
-        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
-            Some(Instant { t: self.t.checked_sub_duration(other)? })
-        }
+    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+        self.t.sub_timespec(&other.t).ok()
     }
 
-    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()
-        }
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant { t: self.t.checked_add_duration(other)? })
     }
 
-    impl SystemTime {
-        pub fn now() -> SystemTime {
-            SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
-        }
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant { t: self.t.checked_sub_duration(other)? })
     }
+}
 
-    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() })
-        }
+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 90ac0098dec..91c010ef2b5 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -111,7 +111,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)]                            |
@@ -123,7 +123,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.
 ///
@@ -224,7 +223,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)]                             |
@@ -233,7 +232,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