Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add env var to override sys::Instant::actually_monotonic() for windows and unix #84448

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions library/std/src/sys/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
#![allow(dead_code)]

pub mod alloc;
pub mod time;
35 changes: 35 additions & 0 deletions library/std/src/sys/common/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::env;
use crate::sync::atomic::{AtomicU8, Ordering};

#[repr(u8)]
#[derive(Copy, Clone)]
pub enum InstantReliability {
// 0 is the placeholder for initialization pending
Default = 1,
AssumeMonotonic = 2,
AssumeBroken = 3,
}

static INSTANT_RELIABILITY: AtomicU8 = AtomicU8::new(0);

pub fn instant_reliability_override() -> InstantReliability {
let current = INSTANT_RELIABILITY.load(Ordering::Relaxed);

if current == 0 {
let new = match env::var("RUST_CLOCK_ASSUME_MONOTONIC").as_deref() {
Ok("1") => InstantReliability::AssumeMonotonic,
Ok("0") => InstantReliability::AssumeBroken,
Ok(_) => {
eprintln!("unsupported value in RUST_CLOCK_ASSUME_MONOTONIC; using default");
InstantReliability::Default
}
_ => InstantReliability::Default,
};
INSTANT_RELIABILITY.store(new as u8, Ordering::Relaxed);
new
} else {
Comment on lines +19 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, just passing by - should this be a nested #[cold] function with the outer function marked #[inline]? Just to reduce the best-case cost of actually_monotonic

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

although maybe this isn't relevant at all anymore? If so nevermind

// SAFETY: The enum has a compatible layout and after initialization only values
// cast from enum variants are stored in the atomic static.
unsafe { crate::mem::transmute(current) }
}
}
16 changes: 11 additions & 5 deletions library/std/src/sys/unix/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,12 +273,12 @@ mod inner {

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
use super::Timespec;
use crate::fmt;
use crate::sys::common::time::{instant_reliability_override, InstantReliability};
use crate::sys::cvt;
use crate::time::Duration;

use super::Timespec;

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant {
t: Timespec,
Expand All @@ -301,9 +301,15 @@ mod inner {
}

pub fn actually_monotonic() -> bool {
(cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
|| (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
|| cfg!(target_os = "fuchsia")
match instant_reliability_override() {
InstantReliability::Default => {
(cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
|| (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
|| cfg!(target_os = "fuchsia")
}
InstantReliability::AssumeMonotonic => true,
InstantReliability::AssumeBroken => false,
}
}

pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
Expand Down
7 changes: 6 additions & 1 deletion library/std/src/sys/windows/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::convert::TryInto;
use crate::fmt;
use crate::mem;
use crate::sys::c;
use crate::sys::common::time::{instant_reliability_override, InstantReliability};
use crate::time::Duration;

use core::hash::{Hash, Hasher};
Expand Down Expand Up @@ -42,7 +43,11 @@ impl Instant {
}

pub fn actually_monotonic() -> bool {
false
match instant_reliability_override() {
InstantReliability::Default => false,
InstantReliability::AssumeMonotonic => true,
InstantReliability::AssumeBroken => false,
}
}

pub const fn zero() -> Instant {
Expand Down
26 changes: 25 additions & 1 deletion library/std/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,28 @@ pub use core::time::Duration;
/// > structure cannot represent the new point in time.
///
/// [`add`]: Instant::add
///
/// ## Reliability
///
/// On platforms where the underlying system call's API contract guarantees monotonicity
/// Instant may rely on that property. Otherwise it will add its own synchronization
/// to ensure monotonicity. Sometimes operating system guarantees are broken by hardware
/// or virtualization bugs. This can manifest in Duration between an older and newer Instant
/// appearing to be negative which results in a panic.
///
/// On windows and some unix systems you can override rust's choice to add
/// its own synchronization or rely on the operating system by setting the environment variable
/// `RUST_CLOCK_ASSUME_MONOTONIC` to `1` (trust the system-provided time) or `0`
/// (apply additional synchronization). The value of the variable is only read
/// the first time an Instant is created. Altering it later will have no effect.
///
/// > Note: The environment variable is experimental and meant to diagnose bugs.
/// > It is not part of the normal Rust stability guarantees.
///
/// If you encounter a case where additional synchronization is necessary please
/// [file an issue]
///
/// [file an issue]: https://github.com/rust-lang/rust/issues
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct Instant(time::Instant);
Expand Down Expand Up @@ -327,7 +349,9 @@ impl Instant {
///
/// This function may panic if the current time is earlier than this
/// instant, which is something that can happen if an `Instant` is
/// produced synthetically.
/// produced synthetically or due to [hardware bugs]
///
/// [hardware bugs]: Instant#reliability
///
/// # Examples
///
Expand Down