|
1 | 1 | use crate::fmt;
|
2 | 2 | use crate::time::Duration;
|
3 | 3 |
|
4 |
| -pub use self::inner::Instant; |
5 |
| - |
6 | 4 | const NSEC_PER_SEC: u64 = 1_000_000_000;
|
7 | 5 | pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
|
8 | 6 | #[allow(dead_code)] // Used for pthread condvar timeouts
|
@@ -40,6 +38,10 @@ impl SystemTime {
|
40 | 38 | SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
|
41 | 39 | }
|
42 | 40 |
|
| 41 | + pub fn now() -> SystemTime { |
| 42 | + SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) } |
| 43 | + } |
| 44 | + |
43 | 45 | pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
44 | 46 | self.t.sub_timespec(&other.t)
|
45 | 47 | }
|
@@ -79,6 +81,36 @@ impl Timespec {
|
79 | 81 | Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
|
80 | 82 | }
|
81 | 83 |
|
| 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 | + |
82 | 114 | pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
|
83 | 115 | if self >= other {
|
84 | 116 | // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
|
@@ -216,209 +248,59 @@ impl From<__timespec64> for Timespec {
|
216 | 248 | }
|
217 | 249 | }
|
218 | 250 |
|
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, |
338 | 254 | }
|
339 | 255 |
|
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) } |
357 | 284 | }
|
358 | 285 |
|
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() |
379 | 288 | }
|
380 | 289 |
|
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)? }) |
388 | 292 | }
|
389 | 293 |
|
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)? }) |
394 | 296 | }
|
| 297 | +} |
395 | 298 |
|
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() |
423 | 305 | }
|
424 | 306 | }
|
0 commit comments