implement CLOCK_MONOTONIC on Linux

This commit is contained in:
Ralf Jung 2020-03-19 23:00:02 +01:00
parent 0ff05c4cfe
commit 4608b94bd8
4 changed files with 35 additions and 26 deletions

View File

@ -5,6 +5,7 @@ use std::borrow::Cow;
use std::cell::RefCell;
use std::num::NonZeroU64;
use std::rc::Rc;
use std::time::Instant;
use rand::rngs::StdRng;
@ -164,6 +165,9 @@ pub struct Evaluator<'tcx> {
/// the call to `miri_start_panic` (the panic payload) when unwinding.
/// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`.
pub(crate) panic_payload: Option<Scalar<Tag>>,
/// The "time anchor" for this machine's monotone clock (for `Instant` simulation).
pub(crate) time_anchor: Instant,
}
impl<'tcx> Evaluator<'tcx> {
@ -182,6 +186,7 @@ impl<'tcx> Evaluator<'tcx> {
file_handler: Default::default(),
dir_handler: Default::default(),
panic_payload: None,
time_anchor: Instant::now(),
}
}
}

View File

@ -1,14 +1,9 @@
use std::time::{Duration, SystemTime};
use std::time::{Duration, SystemTime, Instant};
use crate::stacked_borrows::Tag;
use crate::*;
use helpers::immty_from_int_checked;
// Returns the time elapsed between now and the unix epoch as a `Duration`.
fn get_time<'tcx>() -> InterpResult<'tcx, Duration> {
system_time_to_duration(&SystemTime::now())
}
/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
time.duration_since(SystemTime::UNIX_EPOCH)
@ -28,15 +23,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.check_no_isolation("clock_gettime")?;
let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? {
let tp = this.deref_operand(tp_op)?;
let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? {
system_time_to_duration(&SystemTime::now())?
} else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
// Absolute time does not matter, only relative time does, so we can just
// use our own time anchor here.
Instant::now().duration_since(this.machine.time_anchor)
} else {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
return Ok(-1);
}
};
let tp = this.deref_operand(tp_op)?;
let duration = get_time()?;
let tv_sec = duration.as_secs();
let tv_nsec = duration.subsec_nanos();
@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let tv = this.deref_operand(tv_op)?;
let duration = get_time()?;
let duration = system_time_to_duration(&SystemTime::now())?;
let tv_sec = duration.as_secs();
let tv_usec = duration.subsec_micros();

View File

@ -1,14 +0,0 @@
// ignore-windows: TODO clock shims are not implemented on Windows
// compile-flags: -Zmiri-disable-isolation
use std::time::SystemTime;
fn main() {
let now1 = SystemTime::now();
// Do some work to make time pass.
for _ in 0..10 { drop(vec![42]); }
let now2 = SystemTime::now();
assert!(now2 > now1);
}

18
tests/run-pass/time.rs Normal file
View File

@ -0,0 +1,18 @@
// ignore-windows: TODO clock shims are not implemented on Windows
// compile-flags: -Zmiri-disable-isolation
use std::time::{SystemTime, Instant};
fn main() {
let now1 = SystemTime::now();
// Do some work to make time pass.
for _ in 0..10 { drop(vec![42]); }
let now2 = SystemTime::now();
assert!(now2 > now1);
let now1 = Instant::now();
// Do some work to make time pass.
for _ in 0..10 { drop(vec![42]); }
let now2 = Instant::now();
assert!(now2 > now1);
}