Auto merge of #116238 - tamird:gettimeofday, r=thomcc
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 incc367edd95
which predated the introduction of `clock_gettime` support in macOS 10.12 Sierra which became the minimum supported version in58bbca958d
. 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 incc367edd95
which predated the introduction of `clock_gettime` support in macOS 10.12 Sierra which became the minimum supported version in58bbca958d
. Note that this change was made for aarch64 in5008a317ce
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.
This commit is contained in:
commit
e918db897d
2 changed files with 81 additions and 201 deletions
|
@ -1,8 +1,6 @@
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::time::Duration;
|
use crate::time::Duration;
|
||||||
|
|
||||||
pub use self::inner::Instant;
|
|
||||||
|
|
||||||
const NSEC_PER_SEC: u64 = 1_000_000_000;
|
const NSEC_PER_SEC: u64 = 1_000_000_000;
|
||||||
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
|
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
|
||||||
#[allow(dead_code)] // Used for pthread condvar timeouts
|
#[allow(dead_code)] // Used for pthread condvar timeouts
|
||||||
|
@ -40,6 +38,10 @@ impl SystemTime {
|
||||||
SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
|
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> {
|
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||||
self.t.sub_timespec(&other.t)
|
self.t.sub_timespec(&other.t)
|
||||||
}
|
}
|
||||||
|
@ -79,6 +81,36 @@ impl Timespec {
|
||||||
Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
|
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> {
|
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
|
||||||
if self >= other {
|
if self >= other {
|
||||||
// NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
|
// NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
|
||||||
|
@ -216,209 +248,59 @@ impl From<__timespec64> for Timespec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
all(target_os = "macos", any(not(target_arch = "aarch64"))),
|
pub struct Instant {
|
||||||
target_os = "ios",
|
t: Timespec,
|
||||||
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};
|
impl Instant {
|
||||||
|
pub fn now() -> Instant {
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
// https://www.manpagez.com/man/3/clock_gettime/
|
||||||
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`
|
// CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
|
||||||
// operations, as we are only interested in the effects on a single
|
// ner as CLOCK_MONOTONIC_RAW, but that does not incre-
|
||||||
// memory location.
|
// ment while the system is asleep. The returned value
|
||||||
static INFO_BITS: AtomicU64 = AtomicU64::new(0);
|
// is identical to the result of mach_absolute_time()
|
||||||
|
// after the appropriate mach_timebase conversion is
|
||||||
// If a previous thread has initialized `INFO_BITS`, use it.
|
// applied.
|
||||||
let info_bits = INFO_BITS.load(Ordering::Relaxed);
|
//
|
||||||
if info_bits != 0 {
|
// Instant on macos was historically implemented using mach_absolute_time;
|
||||||
return info_from_bits(info_bits);
|
// we preserve this value domain out of an abundance of caution.
|
||||||
}
|
#[cfg(any(
|
||||||
|
target_os = "macos",
|
||||||
// ... otherwise learn for ourselves ...
|
target_os = "ios",
|
||||||
extern "C" {
|
target_os = "watchos",
|
||||||
fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
|
target_os = "tvos"
|
||||||
}
|
))]
|
||||||
|
const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
|
||||||
let mut info = info_from_bits(0);
|
#[cfg(not(any(
|
||||||
unsafe {
|
target_os = "macos",
|
||||||
mach_timebase_info(&mut info);
|
target_os = "ios",
|
||||||
}
|
target_os = "watchos",
|
||||||
INFO_BITS.store(info_to_bits(info), Ordering::Relaxed);
|
target_os = "tvos"
|
||||||
info
|
)))]
|
||||||
|
const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC;
|
||||||
|
Instant { t: Timespec::now(clock_id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||||
fn info_to_bits(info: mach_timebase_info) -> u64 {
|
self.t.sub_timespec(&other.t).ok()
|
||||||
((info.denom as u64) << 32) | (info.numer as u64)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
fn info_from_bits(bits: u64) -> mach_timebase_info {
|
Some(Instant { t: self.t.checked_add_duration(other)? })
|
||||||
mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
|
}
|
||||||
|
|
||||||
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
|
Some(Instant { t: self.t.checked_sub_duration(other)? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(
|
impl fmt::Debug for Instant {
|
||||||
all(target_os = "macos", any(not(target_arch = "aarch64"))),
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
target_os = "ios",
|
f.debug_struct("Instant")
|
||||||
target_os = "watchos",
|
.field("tv_sec", &self.t.tv_sec)
|
||||||
target_os = "tvos"
|
.field("tv_nsec", &self.t.tv_nsec.0)
|
||||||
)))]
|
.finish()
|
||||||
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 {
|
|
||||||
#[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)? })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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() })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ pub use core::time::TryFromFloatSecsError;
|
||||||
/// |-----------|----------------------------------------------------------------------|
|
/// |-----------|----------------------------------------------------------------------|
|
||||||
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
|
||||||
/// | UNIX | [clock_gettime (Monotonic Clock)] |
|
/// | UNIX | [clock_gettime (Monotonic Clock)] |
|
||||||
/// | Darwin | [mach_absolute_time] |
|
/// | Darwin | [clock_gettime (Monotonic Clock)] |
|
||||||
/// | VXWorks | [clock_gettime (Monotonic Clock)] |
|
/// | VXWorks | [clock_gettime (Monotonic Clock)] |
|
||||||
/// | SOLID | `get_tim` |
|
/// | SOLID | `get_tim` |
|
||||||
/// | WASI | [__wasi_clock_time_get (Monotonic Clock)] |
|
/// | 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
|
/// [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
|
/// [__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
|
/// [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.
|
/// **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] |
|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
|
||||||
/// | UNIX | [clock_gettime (Realtime Clock)] |
|
/// | UNIX | [clock_gettime (Realtime Clock)] |
|
||||||
/// | Darwin | [gettimeofday] |
|
/// | Darwin | [clock_gettime (Realtime Clock)] |
|
||||||
/// | VXWorks | [clock_gettime (Realtime Clock)] |
|
/// | VXWorks | [clock_gettime (Realtime Clock)] |
|
||||||
/// | SOLID | `SOLID_RTC_ReadTime` |
|
/// | SOLID | `SOLID_RTC_ReadTime` |
|
||||||
/// | WASI | [__wasi_clock_time_get (Realtime Clock)] |
|
/// | WASI | [__wasi_clock_time_get (Realtime Clock)] |
|
||||||
|
@ -233,7 +232,6 @@ pub struct Instant(time::Instant);
|
||||||
/// [currently]: crate::io#platform-specific-behavior
|
/// [currently]: crate::io#platform-specific-behavior
|
||||||
/// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time
|
/// [`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
|
/// [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
|
/// [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
|
/// [__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
|
/// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue