@@ -270,22 +270,25 @@ pub struct Instant {
270270}
271271
272272impl Instant {
273+ // CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
274+ // ner as CLOCK_MONOTONIC_RAW, but that does not incre-
275+ // ment while the system is asleep. The returned value
276+ // is identical to the result of mach_absolute_time()
277+ // after the appropriate mach_timebase conversion is
278+ // applied.
279+ //
280+ // We use `CLOCK_UPTIME_RAW` instead of `CLOCK_MONOTONIC` since
281+ // `CLOCK_UPTIME_RAW` is based on `mach_absolute_time`, which is the
282+ // clock that all timeouts and deadlines are measured against inside
283+ // the kernel.
273284 #[ cfg( target_vendor = "apple" ) ]
274285 pub ( crate ) const CLOCK_ID : libc:: clockid_t = libc:: CLOCK_UPTIME_RAW ;
286+
275287 #[ cfg( not( target_vendor = "apple" ) ) ]
276288 pub ( crate ) const CLOCK_ID : libc:: clockid_t = libc:: CLOCK_MONOTONIC ;
289+
277290 pub fn now ( ) -> Instant {
278291 // https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html
279- //
280- // CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
281- // ner as CLOCK_MONOTONIC_RAW, but that does not incre-
282- // ment while the system is asleep. The returned value
283- // is identical to the result of mach_absolute_time()
284- // after the appropriate mach_timebase conversion is
285- // applied.
286- //
287- // Instant on macos was historically implemented using mach_absolute_time;
288- // we preserve this value domain out of an abundance of caution.
289292 Instant { t : Timespec :: now ( Self :: CLOCK_ID ) }
290293 }
291294
@@ -308,6 +311,37 @@ impl Instant {
308311 pub ( crate ) fn into_timespec ( self ) -> Timespec {
309312 self . t
310313 }
314+
315+ /// Returns `self` converted into units of `mach_absolute_time`, or `None`
316+ /// if `self` is before the system boot time. If the conversion cannot be
317+ /// performed precisely, this ceils the result up to the nearest
318+ /// representable value.
319+ #[ cfg( target_vendor = "apple" ) ]
320+ pub fn into_mach_absolute_time_ceil ( self ) -> Option < u128 > {
321+ #[ repr( C ) ]
322+ struct mach_timebase_info {
323+ numer : u32 ,
324+ denom : u32 ,
325+ }
326+
327+ unsafe extern "C" {
328+ unsafe fn mach_timebase_info ( info : * mut mach_timebase_info ) -> libc:: kern_return_t ;
329+ }
330+
331+ let secs = u64:: try_from ( self . t . tv_sec ) . ok ( ) ?;
332+
333+ let mut timebase = mach_timebase_info { numer : 0 , denom : 0 } ;
334+ assert_eq ! ( unsafe { mach_timebase_info( & mut timebase) } , libc:: KERN_SUCCESS ) ;
335+
336+ // Since `tv_sec` is 64-bit and `tv_nsec` is smaller than 1 billion,
337+ // this cannot overflow. The resulting number needs at most 94 bits.
338+ let nanos =
339+ u128:: from ( secs) * u128:: from ( NSEC_PER_SEC ) + u128:: from ( self . t . tv_nsec . as_inner ( ) ) ;
340+ // This multiplication cannot overflow since multiplying a 94-bit
341+ // number by a 32-bit number yields a number that needs at most
342+ // 126 bits.
343+ Some ( ( nanos * u128:: from( timebase. denom) ) . div_ceil( u128:: from( timebase. numer) ) )
344+ }
311345}
312346
313347impl AsInner < Timespec > for Instant {
0 commit comments