Merge pull request #4242 from RalfJung/clock-names
machine clock: make 'monotonic' explicit
This commit is contained in:
commit
99ce8fc8db
5 changed files with 34 additions and 30 deletions
|
|
@ -62,12 +62,12 @@ impl Instant {
|
|||
|
||||
/// A monotone clock used for `Instant` simulation.
|
||||
#[derive(Debug)]
|
||||
pub struct Clock {
|
||||
kind: ClockKind,
|
||||
pub struct MonotonicClock {
|
||||
kind: MonotonicClockKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ClockKind {
|
||||
enum MonotonicClockKind {
|
||||
Host {
|
||||
/// The "epoch" for this machine's monotone clock:
|
||||
/// the moment we consider to be time = 0.
|
||||
|
|
@ -79,13 +79,13 @@ enum ClockKind {
|
|||
},
|
||||
}
|
||||
|
||||
impl Clock {
|
||||
impl MonotonicClock {
|
||||
/// Create a new clock based on the availability of communication with the host.
|
||||
pub fn new(communicate: bool) -> Self {
|
||||
let kind = if communicate {
|
||||
ClockKind::Host { epoch: StdInstant::now() }
|
||||
MonotonicClockKind::Host { epoch: StdInstant::now() }
|
||||
} else {
|
||||
ClockKind::Virtual { nanoseconds: 0.into() }
|
||||
MonotonicClockKind::Virtual { nanoseconds: 0.into() }
|
||||
};
|
||||
|
||||
Self { kind }
|
||||
|
|
@ -94,10 +94,10 @@ impl Clock {
|
|||
/// Let the time pass for a small interval.
|
||||
pub fn tick(&self) {
|
||||
match &self.kind {
|
||||
ClockKind::Host { .. } => {
|
||||
MonotonicClockKind::Host { .. } => {
|
||||
// Time will pass without us doing anything.
|
||||
}
|
||||
ClockKind::Virtual { nanoseconds } => {
|
||||
MonotonicClockKind::Virtual { nanoseconds } => {
|
||||
nanoseconds.update(|x| x + NANOSECONDS_PER_BASIC_BLOCK);
|
||||
}
|
||||
}
|
||||
|
|
@ -106,8 +106,8 @@ impl Clock {
|
|||
/// Sleep for the desired duration.
|
||||
pub fn sleep(&self, duration: Duration) {
|
||||
match &self.kind {
|
||||
ClockKind::Host { .. } => std::thread::sleep(duration),
|
||||
ClockKind::Virtual { nanoseconds } => {
|
||||
MonotonicClockKind::Host { .. } => std::thread::sleep(duration),
|
||||
MonotonicClockKind::Virtual { nanoseconds } => {
|
||||
// Just pretend that we have slept for some time.
|
||||
let nanos: u128 = duration.as_nanos();
|
||||
nanoseconds.update(|x| {
|
||||
|
|
@ -121,15 +121,17 @@ impl Clock {
|
|||
/// Return the `epoch` instant (time = 0), to convert between monotone instants and absolute durations.
|
||||
pub fn epoch(&self) -> Instant {
|
||||
match &self.kind {
|
||||
ClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) },
|
||||
ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
|
||||
MonotonicClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) },
|
||||
MonotonicClockKind::Virtual { .. } =>
|
||||
Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn now(&self) -> Instant {
|
||||
match &self.kind {
|
||||
ClockKind::Host { .. } => Instant { kind: InstantKind::Host(StdInstant::now()) },
|
||||
ClockKind::Virtual { nanoseconds } =>
|
||||
MonotonicClockKind::Host { .. } =>
|
||||
Instant { kind: InstantKind::Host(StdInstant::now()) },
|
||||
MonotonicClockKind::Virtual { nanoseconds } =>
|
||||
Instant { kind: InstantKind::Virtual { nanoseconds: nanoseconds.get() } },
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ enum Timeout {
|
|||
|
||||
impl Timeout {
|
||||
/// How long do we have to wait from now until the specified time?
|
||||
fn get_wait_time(&self, clock: &Clock) -> Duration {
|
||||
fn get_wait_time(&self, clock: &MonotonicClock) -> Duration {
|
||||
match self {
|
||||
Timeout::Monotonic(instant) => instant.duration_since(clock.now()),
|
||||
Timeout::RealTime(time) =>
|
||||
|
|
@ -683,7 +683,7 @@ impl<'tcx> ThreadManager<'tcx> {
|
|||
}
|
||||
|
||||
/// Get the wait time for the next timeout, or `None` if no timeout is pending.
|
||||
fn next_callback_wait_time(&self, clock: &Clock) -> Option<Duration> {
|
||||
fn next_callback_wait_time(&self, clock: &MonotonicClock) -> Option<Duration> {
|
||||
self.threads
|
||||
.iter()
|
||||
.filter_map(|t| {
|
||||
|
|
@ -702,7 +702,7 @@ impl<'tcx> ThreadManager<'tcx> {
|
|||
/// used in stateless model checkers such as Loom: run the active thread as
|
||||
/// long as we can and switch only when we have to (the active thread was
|
||||
/// blocked, terminated, or has explicitly asked to be preempted).
|
||||
fn schedule(&mut self, clock: &Clock) -> InterpResult<'tcx, SchedulingAction> {
|
||||
fn schedule(&mut self, clock: &MonotonicClock) -> InterpResult<'tcx, SchedulingAction> {
|
||||
// This thread and the program can keep going.
|
||||
if self.threads[self.active_thread].state.is_enabled() && !self.yield_active_thread {
|
||||
// The currently active thread is still enabled, just continue with it.
|
||||
|
|
@ -772,7 +772,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
|
|||
for (id, thread) in this.machine.threads.threads.iter_enumerated_mut() {
|
||||
match &thread.state {
|
||||
ThreadState::Blocked { timeout: Some(timeout), .. }
|
||||
if timeout.get_wait_time(&this.machine.clock) == Duration::ZERO =>
|
||||
if timeout.get_wait_time(&this.machine.monotonic_clock) == Duration::ZERO =>
|
||||
{
|
||||
let old_state = mem::replace(&mut thread.state, ThreadState::Enabled);
|
||||
let ThreadState::Blocked { callback, .. } = old_state else { unreachable!() };
|
||||
|
|
@ -1006,8 +1006,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
TimeoutClock::Monotonic =>
|
||||
Timeout::Monotonic(match anchor {
|
||||
TimeoutAnchor::Absolute => this.machine.clock.epoch(),
|
||||
TimeoutAnchor::Relative => this.machine.clock.now(),
|
||||
TimeoutAnchor::Absolute => this.machine.monotonic_clock.epoch(),
|
||||
TimeoutAnchor::Relative => this.machine.monotonic_clock.now(),
|
||||
}),
|
||||
};
|
||||
anchor.add_lossy(duration)
|
||||
|
|
@ -1152,7 +1152,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.machine.handle_abnormal_termination();
|
||||
throw_machine_stop!(TerminationInfo::Interrupted);
|
||||
}
|
||||
match this.machine.threads.schedule(&this.machine.clock)? {
|
||||
match this.machine.threads.schedule(&this.machine.monotonic_clock)? {
|
||||
SchedulingAction::ExecuteStep => {
|
||||
if !this.step()? {
|
||||
// See if this thread can do something else.
|
||||
|
|
@ -1167,7 +1167,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.run_timeout_callback()?;
|
||||
}
|
||||
SchedulingAction::Sleep(duration) => {
|
||||
this.machine.clock.sleep(duration);
|
||||
this.machine.monotonic_clock.sleep(duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ pub use crate::borrow_tracker::stacked_borrows::{
|
|||
};
|
||||
pub use crate::borrow_tracker::tree_borrows::{EvalContextExt as _, Tree};
|
||||
pub use crate::borrow_tracker::{BorTag, BorrowTrackerMethod, EvalContextExt as _, RetagFields};
|
||||
pub use crate::clock::{Clock, Instant};
|
||||
pub use crate::clock::{Instant, MonotonicClock};
|
||||
pub use crate::concurrency::cpu_affinity::MAX_CPUS;
|
||||
pub use crate::concurrency::data_race::{
|
||||
AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _,
|
||||
|
|
|
|||
|
|
@ -486,7 +486,7 @@ pub struct MiriMachine<'tcx> {
|
|||
pub(crate) epoll_interests: shims::EpollInterestTable,
|
||||
|
||||
/// This machine's monotone clock.
|
||||
pub(crate) clock: Clock,
|
||||
pub(crate) monotonic_clock: MonotonicClock,
|
||||
|
||||
/// The set of threads.
|
||||
pub(crate) threads: ThreadManager<'tcx>,
|
||||
|
|
@ -713,7 +713,7 @@ impl<'tcx> MiriMachine<'tcx> {
|
|||
preemption_rate: config.preemption_rate,
|
||||
report_progress: config.report_progress,
|
||||
basic_block_count: 0,
|
||||
clock: Clock::new(config.isolated_op == IsolatedOp::Allow),
|
||||
monotonic_clock: MonotonicClock::new(config.isolated_op == IsolatedOp::Allow),
|
||||
#[cfg(unix)]
|
||||
native_lib: config.native_lib.as_ref().map(|lib_file_path| {
|
||||
let host_triple = rustc_session::config::host_tuple();
|
||||
|
|
@ -896,7 +896,7 @@ impl VisitProvenance for MiriMachine<'_> {
|
|||
tcx: _,
|
||||
isolated_op: _,
|
||||
validation: _,
|
||||
clock: _,
|
||||
monotonic_clock: _,
|
||||
layouts: _,
|
||||
static_roots: _,
|
||||
profiler: _,
|
||||
|
|
@ -1568,7 +1568,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||
ecx.maybe_preempt_active_thread();
|
||||
|
||||
// Make sure some time passes.
|
||||
ecx.machine.clock.tick();
|
||||
ecx.machine.monotonic_clock.tick();
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?;
|
||||
system_time_to_duration(&SystemTime::now())?
|
||||
} else if relative_clocks.contains(&clk_id) {
|
||||
this.machine.clock.now().duration_since(this.machine.clock.epoch())
|
||||
this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch())
|
||||
} else {
|
||||
return this.set_last_error_and_return_i32(LibcError("EINVAL"));
|
||||
};
|
||||
|
|
@ -248,7 +248,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
// QueryPerformanceCounter uses a hardware counter as its basis.
|
||||
// Miri will emulate a counter with a resolution of 1 nanosecond.
|
||||
let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch());
|
||||
let duration =
|
||||
this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch());
|
||||
let qpc = i64::try_from(duration.as_nanos()).map_err(|_| {
|
||||
err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported")
|
||||
})?;
|
||||
|
|
@ -287,7 +288,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
// This returns a u64, with time units determined dynamically by `mach_timebase_info`.
|
||||
// We return plain nanoseconds.
|
||||
let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch());
|
||||
let duration =
|
||||
this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch());
|
||||
let res = u64::try_from(duration.as_nanos()).map_err(|_| {
|
||||
err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported")
|
||||
})?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue