Skip to content

Commit e918db8

Browse files
committed
Auto merge of rust-lang#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 in time-rs/time@cc367ed which predated the introduction of `clock_gettime` support in macOS 10.12 Sierra which became the minimum supported version in 58bbca9. 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 time-rs/time@cc367ed which predated the introduction of `clock_gettime` support in macOS 10.12 Sierra which became the minimum supported version in 58bbca9. Note that this change was made for aarch64 in 5008a31 which predated 10.12 becoming the minimum supported version. The discussion took place in rust-lang#91417 and in particular rust-lang#91417 (comment) and rust-lang#91417 (comment) are relevant.
2 parents f1a5ce1 + bc30010 commit e918db8

File tree

2 files changed

+80
-200
lines changed

2 files changed

+80
-200
lines changed

library/std/src/sys/unix/time.rs

+78-196
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use crate::fmt;
22
use crate::time::Duration;
33

4-
pub use self::inner::Instant;
5-
64
const NSEC_PER_SEC: u64 = 1_000_000_000;
75
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
86
#[allow(dead_code)] // Used for pthread condvar timeouts
@@ -40,6 +38,10 @@ impl SystemTime {
4038
SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
4139
}
4240

41+
pub fn now() -> SystemTime {
42+
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
43+
}
44+
4345
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
4446
self.t.sub_timespec(&other.t)
4547
}
@@ -79,6 +81,36 @@ impl Timespec {
7981
Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
8082
}
8183

84+
pub fn now(clock: libc::clockid_t) -> Timespec {
85+
use crate::mem::MaybeUninit;
86+
use crate::sys::cvt;
87+
88+
// Try to use 64-bit time in preparation for Y2038.
89+
#[cfg(all(
90+
target_os = "linux",
91+
target_env = "gnu",
92+
target_pointer_width = "32",
93+
not(target_arch = "riscv32")
94+
))]
95+
{
96+
use crate::sys::weak::weak;
97+
98+
// __clock_gettime64 was added to 32-bit arches in glibc 2.34,
99+
// and it handles both vDSO calls and ENOSYS fallbacks itself.
100+
weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int);
101+
102+
if let Some(clock_gettime64) = __clock_gettime64.get() {
103+
let mut t = MaybeUninit::uninit();
104+
cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
105+
return Timespec::from(unsafe { t.assume_init() });
106+
}
107+
}
108+
109+
let mut t = MaybeUninit::uninit();
110+
cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
111+
Timespec::from(unsafe { t.assume_init() })
112+
}
113+
82114
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
83115
if self >= other {
84116
// NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
@@ -216,209 +248,59 @@ impl From<__timespec64> for Timespec {
216248
}
217249
}
218250

219-
#[cfg(any(
220-
all(target_os = "macos", any(not(target_arch = "aarch64"))),
221-
target_os = "ios",
222-
target_os = "watchos",
223-
target_os = "tvos"
224-
))]
225-
mod inner {
226-
use crate::sync::atomic::{AtomicU64, Ordering};
227-
use crate::sys::cvt;
228-
use crate::sys_common::mul_div_u64;
229-
use crate::time::Duration;
230-
231-
use super::{SystemTime, Timespec, NSEC_PER_SEC};
232-
233-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
234-
pub struct Instant {
235-
t: u64,
236-
}
237-
238-
#[repr(C)]
239-
#[derive(Copy, Clone)]
240-
struct mach_timebase_info {
241-
numer: u32,
242-
denom: u32,
243-
}
244-
type mach_timebase_info_t = *mut mach_timebase_info;
245-
type kern_return_t = libc::c_int;
246-
247-
impl Instant {
248-
pub fn now() -> Instant {
249-
extern "C" {
250-
fn mach_absolute_time() -> u64;
251-
}
252-
Instant { t: unsafe { mach_absolute_time() } }
253-
}
254-
255-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
256-
let diff = self.t.checked_sub(other.t)?;
257-
let info = info();
258-
let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
259-
Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
260-
}
261-
262-
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
263-
Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
264-
}
265-
266-
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
267-
Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
268-
}
269-
}
270-
271-
impl SystemTime {
272-
pub fn now() -> SystemTime {
273-
use crate::ptr;
274-
275-
let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 };
276-
cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
277-
return SystemTime::from(s);
278-
}
279-
}
280-
281-
impl From<libc::timeval> for Timespec {
282-
fn from(t: libc::timeval) -> Timespec {
283-
Timespec::new(t.tv_sec as i64, 1000 * t.tv_usec as i64)
284-
}
285-
}
286-
287-
impl From<libc::timeval> for SystemTime {
288-
fn from(t: libc::timeval) -> SystemTime {
289-
SystemTime { t: Timespec::from(t) }
290-
}
291-
}
292-
293-
fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
294-
let nanos =
295-
dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?;
296-
let info = info();
297-
Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
298-
}
299-
300-
fn info() -> mach_timebase_info {
301-
// INFO_BITS conceptually is an `Option<mach_timebase_info>`. We can do
302-
// this in 64 bits because we know 0 is never a valid value for the
303-
// `denom` field.
304-
//
305-
// Encoding this as a single `AtomicU64` allows us to use `Relaxed`
306-
// operations, as we are only interested in the effects on a single
307-
// memory location.
308-
static INFO_BITS: AtomicU64 = AtomicU64::new(0);
309-
310-
// If a previous thread has initialized `INFO_BITS`, use it.
311-
let info_bits = INFO_BITS.load(Ordering::Relaxed);
312-
if info_bits != 0 {
313-
return info_from_bits(info_bits);
314-
}
315-
316-
// ... otherwise learn for ourselves ...
317-
extern "C" {
318-
fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
319-
}
320-
321-
let mut info = info_from_bits(0);
322-
unsafe {
323-
mach_timebase_info(&mut info);
324-
}
325-
INFO_BITS.store(info_to_bits(info), Ordering::Relaxed);
326-
info
327-
}
328-
329-
#[inline]
330-
fn info_to_bits(info: mach_timebase_info) -> u64 {
331-
((info.denom as u64) << 32) | (info.numer as u64)
332-
}
333-
334-
#[inline]
335-
fn info_from_bits(bits: u64) -> mach_timebase_info {
336-
mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
337-
}
251+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
252+
pub struct Instant {
253+
t: Timespec,
338254
}
339255

340-
#[cfg(not(any(
341-
all(target_os = "macos", any(not(target_arch = "aarch64"))),
342-
target_os = "ios",
343-
target_os = "watchos",
344-
target_os = "tvos"
345-
)))]
346-
mod inner {
347-
use crate::fmt;
348-
use crate::mem::MaybeUninit;
349-
use crate::sys::cvt;
350-
use crate::time::Duration;
351-
352-
use super::{SystemTime, Timespec};
353-
354-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
355-
pub struct Instant {
356-
t: Timespec,
256+
impl Instant {
257+
pub fn now() -> Instant {
258+
// https://www.manpagez.com/man/3/clock_gettime/
259+
//
260+
// CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
261+
// ner as CLOCK_MONOTONIC_RAW, but that does not incre-
262+
// ment while the system is asleep. The returned value
263+
// is identical to the result of mach_absolute_time()
264+
// after the appropriate mach_timebase conversion is
265+
// applied.
266+
//
267+
// Instant on macos was historically implemented using mach_absolute_time;
268+
// we preserve this value domain out of an abundance of caution.
269+
#[cfg(any(
270+
target_os = "macos",
271+
target_os = "ios",
272+
target_os = "watchos",
273+
target_os = "tvos"
274+
))]
275+
const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
276+
#[cfg(not(any(
277+
target_os = "macos",
278+
target_os = "ios",
279+
target_os = "watchos",
280+
target_os = "tvos"
281+
)))]
282+
const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC;
283+
Instant { t: Timespec::now(clock_id) }
357284
}
358285

359-
impl Instant {
360-
pub fn now() -> Instant {
361-
#[cfg(target_os = "macos")]
362-
const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
363-
#[cfg(not(target_os = "macos"))]
364-
const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC;
365-
Instant { t: Timespec::now(clock_id) }
366-
}
367-
368-
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
369-
self.t.sub_timespec(&other.t).ok()
370-
}
371-
372-
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
373-
Some(Instant { t: self.t.checked_add_duration(other)? })
374-
}
375-
376-
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
377-
Some(Instant { t: self.t.checked_sub_duration(other)? })
378-
}
286+
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
287+
self.t.sub_timespec(&other.t).ok()
379288
}
380289

381-
impl fmt::Debug for Instant {
382-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383-
f.debug_struct("Instant")
384-
.field("tv_sec", &self.t.tv_sec)
385-
.field("tv_nsec", &self.t.tv_nsec.0)
386-
.finish()
387-
}
290+
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
291+
Some(Instant { t: self.t.checked_add_duration(other)? })
388292
}
389293

390-
impl SystemTime {
391-
pub fn now() -> SystemTime {
392-
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
393-
}
294+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
295+
Some(Instant { t: self.t.checked_sub_duration(other)? })
394296
}
297+
}
395298

396-
impl Timespec {
397-
pub fn now(clock: libc::clockid_t) -> Timespec {
398-
// Try to use 64-bit time in preparation for Y2038.
399-
#[cfg(all(
400-
target_os = "linux",
401-
target_env = "gnu",
402-
target_pointer_width = "32",
403-
not(target_arch = "riscv32")
404-
))]
405-
{
406-
use crate::sys::weak::weak;
407-
408-
// __clock_gettime64 was added to 32-bit arches in glibc 2.34,
409-
// and it handles both vDSO calls and ENOSYS fallbacks itself.
410-
weak!(fn __clock_gettime64(libc::clockid_t, *mut super::__timespec64) -> libc::c_int);
411-
412-
if let Some(clock_gettime64) = __clock_gettime64.get() {
413-
let mut t = MaybeUninit::uninit();
414-
cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
415-
return Timespec::from(unsafe { t.assume_init() });
416-
}
417-
}
418-
419-
let mut t = MaybeUninit::uninit();
420-
cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
421-
Timespec::from(unsafe { t.assume_init() })
422-
}
299+
impl fmt::Debug for Instant {
300+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301+
f.debug_struct("Instant")
302+
.field("tv_sec", &self.t.tv_sec)
303+
.field("tv_nsec", &self.t.tv_nsec.0)
304+
.finish()
423305
}
424306
}

library/std/src/time.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub use core::time::TryFromFloatSecsError;
111111
/// |-----------|----------------------------------------------------------------------|
112112
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
113113
/// | UNIX | [clock_gettime (Monotonic Clock)] |
114-
/// | Darwin | [mach_absolute_time] |
114+
/// | Darwin | [clock_gettime (Monotonic Clock)] |
115115
/// | VXWorks | [clock_gettime (Monotonic Clock)] |
116116
/// | SOLID | `get_tim` |
117117
/// | WASI | [__wasi_clock_time_get (Monotonic Clock)] |
@@ -123,7 +123,6 @@ pub use core::time::TryFromFloatSecsError;
123123
/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode
124124
/// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get
125125
/// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime
126-
/// [mach_absolute_time]: https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/services/services.html
127126
///
128127
/// **Disclaimer:** These system calls might change over time.
129128
///
@@ -224,7 +223,7 @@ pub struct Instant(time::Instant);
224223
/// |-----------|----------------------------------------------------------------------|
225224
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
226225
/// | UNIX | [clock_gettime (Realtime Clock)] |
227-
/// | Darwin | [gettimeofday] |
226+
/// | Darwin | [clock_gettime (Realtime Clock)] |
228227
/// | VXWorks | [clock_gettime (Realtime Clock)] |
229228
/// | SOLID | `SOLID_RTC_ReadTime` |
230229
/// | WASI | [__wasi_clock_time_get (Realtime Clock)] |
@@ -233,7 +232,6 @@ pub struct Instant(time::Instant);
233232
/// [currently]: crate::io#platform-specific-behavior
234233
/// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time
235234
/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode
236-
/// [gettimeofday]: https://man7.org/linux/man-pages/man2/gettimeofday.2.html
237235
/// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime
238236
/// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get
239237
/// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime

0 commit comments

Comments
 (0)