3131
3232#![ stable( feature = "time" , since = "1.3.0" ) ]
3333
34- mod monotonic;
3534#[ cfg( test) ]
3635mod tests;
3736
@@ -125,6 +124,23 @@ pub use core::time::FromFloatSecsError;
125124/// > structure cannot represent the new point in time.
126125///
127126/// [`add`]: Instant::add
127+ ///
128+ /// ## Monotonicity
129+ ///
130+ /// On all platforms `Instant` will try to use an OS API that guarantees monotonic behavior
131+ /// if available, which is the case for all [tier 1] platforms.
132+ /// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization
133+ /// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks
134+ /// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. [`checked_duration_since`] can
135+ /// be used to detect and handle situations where monotonicity is violated, or `Instant`s are
136+ /// subtracted in the wrong order.
137+ ///
138+ /// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html
139+ /// [`duration_since`]: Instant::duration_since
140+ /// [`elapsed`]: Instant::elapsed
141+ /// [`sub`]: Instant::sub
142+ /// [`checked_duration_since`]: Instant::checked_duration_since
143+ ///
128144#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
129145#[ stable( feature = "time2" , since = "1.8.0" ) ]
130146pub struct Instant ( time:: Instant ) ;
@@ -247,59 +263,12 @@ impl Instant {
247263 #[ must_use]
248264 #[ stable( feature = "time2" , since = "1.8.0" ) ]
249265 pub fn now ( ) -> Instant {
250- let os_now = time:: Instant :: now ( ) ;
251-
252- // And here we come upon a sad state of affairs. The whole point of
253- // `Instant` is that it's monotonically increasing. We've found in the
254- // wild, however, that it's not actually monotonically increasing for
255- // one reason or another. These appear to be OS and hardware level bugs,
256- // and there's not really a whole lot we can do about them. Here's a
257- // taste of what we've found:
258- //
259- // * #48514 - OpenBSD, x86_64
260- // * #49281 - linux arm64 and s390x
261- // * #51648 - windows, x86
262- // * #56560 - windows, x86_64, AWS
263- // * #56612 - windows, x86, vm (?)
264- // * #56940 - linux, arm64
265- // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar
266- // Firefox bug
267- //
268- // It seems that this just happens a lot in the wild.
269- // We're seeing panics across various platforms where consecutive calls
270- // to `Instant::now`, such as via the `elapsed` function, are panicking
271- // as they're going backwards. Placed here is a last-ditch effort to try
272- // to fix things up. We keep a global "latest now" instance which is
273- // returned instead of what the OS says if the OS goes backwards.
274- //
275- // To hopefully mitigate the impact of this, a few platforms are
276- // excluded as "these at least haven't gone backwards yet".
277- //
278- // While issues have been seen on arm64 platforms the Arm architecture
279- // requires that the counter monotonically increases and that it must
280- // provide a uniform view of system time (e.g. it must not be possible
281- // for a core to receive a message from another core with a time stamp
282- // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
283- // there have been a few 64bit SoCs that have bugs which cause time to
284- // not monoticially increase, these have been fixed in the Linux kernel
285- // and we shouldn't penalize all Arm SoCs for those who refuse to
286- // update their kernels:
287- // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1
288- // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10
289- // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11
290- // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12
291- if time:: Instant :: actually_monotonic ( ) {
292- return Instant ( os_now) ;
293- }
294-
295- Instant ( monotonic:: monotonize ( os_now) )
266+ Instant ( time:: Instant :: now ( ) )
296267 }
297268
298- /// Returns the amount of time elapsed from another instant to this one.
299- ///
300- /// # Panics
269+ /// Returns the amount of time elapsed from another instant to this one,
270+ /// or zero duration if that instant is later than this one.
301271 ///
302- /// This function will panic if `earlier` is later than `self`.
303272 ///
304273 /// # Examples
305274 ///
@@ -311,16 +280,22 @@ impl Instant {
311280 /// sleep(Duration::new(1, 0));
312281 /// let new_now = Instant::now();
313282 /// println!("{:?}", new_now.duration_since(now));
283+ /// println!("{:?}", now.duration_since(new_now)); // 0ns
314284 /// ```
315285 #[ must_use]
316286 #[ stable( feature = "time2" , since = "1.8.0" ) ]
317287 pub fn duration_since ( & self , earlier : Instant ) -> Duration {
318- self . 0 . checked_sub_instant ( & earlier. 0 ) . expect ( "supplied instant is later than self" )
288+ self . checked_duration_since ( earlier) . unwrap_or_default ( )
319289 }
320290
321291 /// Returns the amount of time elapsed from another instant to this one,
322292 /// or None if that instant is later than this one.
323293 ///
294+ /// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s,
295+ /// this method can return `None`.
296+ ///
297+ /// [monotonicity bugs]: Instant#monotonicity
298+ ///
324299 /// # Examples
325300 ///
326301 /// ```no_run
@@ -362,12 +337,6 @@ impl Instant {
362337
363338 /// Returns the amount of time elapsed since this instant was created.
364339 ///
365- /// # Panics
366- ///
367- /// This function may panic if the current time is earlier than this
368- /// instant, which is something that can happen if an `Instant` is
369- /// produced synthetically.
370- ///
371340 /// # Examples
372341 ///
373342 /// ```no_run
0 commit comments