Skip to content

Commit 9d8ef11

Browse files
committed
make Instant::{duration_since, elapsed, sub} saturating and remove workarounds
This removes all mutex/atomics based workarounds for non-monotonic clocks and makes the previously panicking methods saturating instead. Effectively this moves the monotonization from `Instant` construction to the comparisons. This has some observable effects, especially on platforms without monotonic clocks: * Incorrectly ordered Instant comparisons no longer panic. This may hide some programming errors until someone actually looks at the resulting `Duration` * `checked_duration_since` will now return `None` in more cases. Previously it only happened when one compared instants obtained in the wrong order or manually created ones. Now it also does on backslides. The upside is reduced complexity and lower overhead of `Instant::now`.
1 parent 5d8767c commit 9d8ef11

File tree

10 files changed

+30
-270
lines changed

10 files changed

+30
-270
lines changed

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,6 @@ impl Instant {
115115
Instant { t: time }
116116
}
117117

118-
pub const fn zero() -> Instant {
119-
Instant { t: Timespec::zero() }
120-
}
121-
122-
pub fn actually_monotonic() -> bool {
123-
true
124-
}
125-
126118
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
127119
self.t.sub_timespec(&other.t).ok()
128120
}

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,6 @@ impl Instant {
1414
}
1515
}
1616

17-
pub const fn zero() -> Instant {
18-
Instant(0)
19-
}
20-
21-
pub fn actually_monotonic() -> bool {
22-
// There are ways to change the system time
23-
false
24-
}
25-
2617
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
2718
self.0.checked_sub(other.0).map(|ticks| {
2819
// `SYSTIM` is measured in microseconds

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@ impl Instant {
2525
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
2626
Some(Instant(self.0.checked_sub(*other)?))
2727
}
28-
29-
pub fn actually_monotonic() -> bool {
30-
false
31-
}
32-
33-
pub const fn zero() -> Instant {
34-
Instant(Duration::from_secs(0))
35-
}
3628
}
3729

3830
impl SystemTime {

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

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,6 @@ mod inner {
154154
Instant { t: unsafe { mach_absolute_time() } }
155155
}
156156

157-
pub const fn zero() -> Instant {
158-
Instant { t: 0 }
159-
}
160-
161-
pub fn actually_monotonic() -> bool {
162-
true
163-
}
164-
165157
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
166158
let diff = self.t.checked_sub(other.t)?;
167159
let info = info();
@@ -296,17 +288,6 @@ mod inner {
296288
Instant { t: now(libc::CLOCK_MONOTONIC) }
297289
}
298290

299-
pub const fn zero() -> Instant {
300-
Instant { t: Timespec::zero() }
301-
}
302-
303-
pub fn actually_monotonic() -> bool {
304-
(cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
305-
|| (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
306-
|| (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64"))
307-
|| cfg!(target_os = "fuchsia")
308-
}
309-
310291
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
311292
self.t.sub_timespec(&other.t).ok()
312293
}

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,6 @@ impl Instant {
1313
panic!("time not implemented on this platform")
1414
}
1515

16-
pub const fn zero() -> Instant {
17-
Instant(Duration::from_secs(0))
18-
}
19-
20-
pub fn actually_monotonic() -> bool {
21-
false
22-
}
23-
2416
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
2517
self.0.checked_sub(other.0)
2618
}

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@ impl Instant {
2525
Instant(current_time(wasi::CLOCKID_MONOTONIC))
2626
}
2727

28-
pub const fn zero() -> Instant {
29-
Instant(Duration::from_secs(0))
30-
}
31-
32-
pub fn actually_monotonic() -> bool {
33-
true
34-
}
35-
3628
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
3729
self.0.checked_sub(other.0)
3830
}

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,6 @@ impl Instant {
4141
perf_counter::PerformanceCounterInstant::now().into()
4242
}
4343

44-
pub fn actually_monotonic() -> bool {
45-
false
46-
}
47-
48-
pub const fn zero() -> Instant {
49-
Instant { t: Duration::from_secs(0) }
50-
}
51-
5244
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
5345
// On windows there's a threshold below which we consider two timestamps
5446
// equivalent due to measurement error. For more details + doc link,

library/std/src/time.rs

Lines changed: 27 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
3232
#![stable(feature = "time", since = "1.3.0")]
3333

34-
mod monotonic;
3534
#[cfg(test)]
3635
mod 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")]
130146
pub 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

library/std/src/time/monotonic.rs

Lines changed: 0 additions & 116 deletions
This file was deleted.

0 commit comments

Comments
 (0)