diff options
| author | Ralf Jung <post@ralfj.de> | 2022-09-01 12:18:55 +0200 |
|---|---|---|
| committer | Christian Poveda <git@pvdrz.com> | 2022-09-13 15:16:41 -0500 |
| commit | bc307b40bad4fe33319db3e61e779aacb853d4ca (patch) | |
| tree | ac90f5770c0e2740c6824055f4d4f5d3e87e09e0 | |
| parent | f5e2f731785029c2fa50f590f41ff14f5e83299d (diff) | |
| download | rust-bc307b40bad4fe33319db3e61e779aacb853d4ca.tar.gz rust-bc307b40bad4fe33319db3e61e779aacb853d4ca.zip | |
organize clock arithmetic more like the stdlib
| -rw-r--r-- | src/clock.rs | 88 | ||||
| -rw-r--r-- | src/concurrency/thread.rs | 2 | ||||
| -rw-r--r-- | src/shims/time.rs | 15 | ||||
| -rw-r--r-- | src/shims/unix/linux/sync.rs | 4 | ||||
| -rw-r--r-- | src/shims/unix/sync.rs | 2 |
5 files changed, 50 insertions, 61 deletions
diff --git a/src/clock.rs b/src/clock.rs index faf2d7fda6c..4fab2b2c5f3 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -20,6 +20,32 @@ enum InstantKind { Virtual { nanoseconds: u64 }, } +impl Instant { + pub fn checked_add(&self, duration: Duration) -> Option<Instant> { + match self.kind { + InstantKind::Host(instant) => + instant.checked_add(duration).map(|i| Instant { kind: InstantKind::Host(i) }), + InstantKind::Virtual { nanoseconds } => + u128::from(nanoseconds) + .checked_add(duration.as_nanos()) + .and_then(|n| u64::try_from(n).ok()) + .map(|nanoseconds| Instant { kind: InstantKind::Virtual { nanoseconds } }), + } + } + + pub fn duration_since(&self, earlier: Instant) -> Duration { + match (&self.kind, earlier.kind) { + (InstantKind::Host(instant), InstantKind::Host(earlier)) => + instant.duration_since(earlier), + ( + InstantKind::Virtual { nanoseconds }, + InstantKind::Virtual { nanoseconds: earlier }, + ) => Duration::from_nanos(nanoseconds.saturating_sub(earlier)), + _ => panic!("all `Instant` must be of the same kind"), + } + } +} + /// A monotone clock used for `Instant` simulation. #[derive(Debug)] pub struct Clock { @@ -50,16 +76,6 @@ impl Clock { Self { kind } } - /// Get the current time relative to this clock. - pub fn get(&self) -> Duration { - match &self.kind { - ClockKind::Host { time_anchor } => - StdInstant::now().saturating_duration_since(*time_anchor), - ClockKind::Virtual { nanoseconds } => - Duration::from_nanos(nanoseconds.load(Ordering::Relaxed)), - } - } - /// Let the time pass for a small interval. pub fn tick(&self) { match &self.kind { @@ -67,7 +83,7 @@ impl Clock { // Time will pass without us doing anything. } ClockKind::Virtual { nanoseconds } => { - nanoseconds.fetch_add(NANOSECOND_PER_BASIC_BLOCK, Ordering::Relaxed); + nanoseconds.fetch_add(NANOSECOND_PER_BASIC_BLOCK, Ordering::SeqCst); } } } @@ -78,54 +94,26 @@ impl Clock { ClockKind::Host { .. } => std::thread::sleep(duration), ClockKind::Virtual { nanoseconds } => { // Just pretend that we have slept for some time. - nanoseconds.fetch_add(duration.as_nanos().try_into().unwrap(), Ordering::Relaxed); + nanoseconds.fetch_add(duration.as_nanos().try_into().unwrap(), Ordering::SeqCst); } } } - /// Compute `now + duration` relative to this clock. - pub fn get_time_relative(&self, duration: Duration) -> Option<Instant> { + /// Return the `anchor` instant, to convert between monotone instants and durations relative to the anchor. + pub fn anchor(&self) -> Instant { match &self.kind { - ClockKind::Host { .. } => - StdInstant::now() - .checked_add(duration) - .map(|instant| Instant { kind: InstantKind::Host(instant) }), - ClockKind::Virtual { nanoseconds } => - nanoseconds - .load(Ordering::Relaxed) - .checked_add(duration.as_nanos().try_into().unwrap()) - .map(|nanoseconds| Instant { kind: InstantKind::Virtual { nanoseconds } }), + ClockKind::Host { time_anchor } => Instant { kind: InstantKind::Host(*time_anchor) }, + ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } }, } } - /// Compute `start + duration` relative to this clock where `start` is the instant of time when - /// this clock was created. - pub fn get_time_absolute(&self, duration: Duration) -> Option<Instant> { + pub fn now(&self) -> Instant { match &self.kind { - ClockKind::Host { time_anchor } => - time_anchor - .checked_add(duration) - .map(|instant| Instant { kind: InstantKind::Host(instant) }), - ClockKind::Virtual { .. } => - Some(Instant { - kind: InstantKind::Virtual { - nanoseconds: duration.as_nanos().try_into().unwrap(), - }, - }), - } - } - - /// Returns the duration until the given instant. - pub fn duration_until(&self, instant: &Instant) -> Duration { - match (&instant.kind, &self.kind) { - (InstantKind::Host(instant), ClockKind::Host { .. }) => - instant.saturating_duration_since(StdInstant::now()), - ( - InstantKind::Virtual { nanoseconds }, - ClockKind::Virtual { nanoseconds: current_ns }, - ) => - Duration::from_nanos(nanoseconds.saturating_sub(current_ns.load(Ordering::Relaxed))), - _ => panic!(), + ClockKind::Host { .. } => Instant { kind: InstantKind::Host(StdInstant::now()) }, + ClockKind::Virtual { nanoseconds } => + Instant { + kind: InstantKind::Virtual { nanoseconds: nanoseconds.load(Ordering::SeqCst) }, + }, } } } diff --git a/src/concurrency/thread.rs b/src/concurrency/thread.rs index b39a6716848..5364b341ae3 100644 --- a/src/concurrency/thread.rs +++ b/src/concurrency/thread.rs @@ -191,7 +191,7 @@ impl Time { /// How long do we have to wait from now until the specified time? fn get_wait_time(&self, clock: &Clock) -> Duration { match self { - Time::Monotonic(instant) => clock.duration_until(instant), + Time::Monotonic(instant) => instant.duration_since(clock.now()), Time::RealTime(time) => time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)), } diff --git a/src/shims/time.rs b/src/shims/time.rs index 46164e478f8..933c298ee4d 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -41,7 +41,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`clock_gettime` with real time clocks")?; system_time_to_duration(&SystemTime::now())? } else if relative_clocks.contains(&clk_id) { - this.machine.clock.get() + this.machine.clock.now().duration_since(this.machine.clock.anchor()) } else { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, '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.get(); + let duration = this.machine.clock.now().duration_since(this.machine.clock.anchor()); let qpc = i64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported") })?; @@ -164,7 +164,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. - let duration = this.machine.clock.get(); + let duration = this.machine.clock.now().duration_since(this.machine.clock.anchor()); let res = u64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported") })?; @@ -207,9 +207,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; // If adding the duration overflows, let's just sleep for an hour. Waking up early is always acceptable. - let timeout_time = this.machine.clock.get_time_relative(duration).unwrap_or_else(|| { - this.machine.clock.get_time_relative(Duration::from_secs(3600)).unwrap() - }); + let now = this.machine.clock.now(); + let timeout_time = now + .checked_add(duration) + .unwrap_or_else(|| now.checked_add(Duration::from_secs(3600)).unwrap()); let active_thread = this.get_active_thread(); this.block_thread(active_thread); @@ -235,7 +236,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let timeout_ms = this.read_scalar(timeout)?.to_u32()?; let duration = Duration::from_millis(timeout_ms.into()); - let timeout_time = this.machine.clock.get_time_relative(duration).unwrap(); + let timeout_time = this.machine.clock.now().checked_add(duration).unwrap(); let active_thread = this.get_active_thread(); this.block_thread(active_thread); diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index b2c2fa14d52..cf5a945c5fa 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -106,14 +106,14 @@ pub fn futex<'tcx>( if op & futex_realtime != 0 { Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) } else { - Time::Monotonic(this.machine.clock.get_time_absolute(duration).unwrap()) + Time::Monotonic(this.machine.clock.anchor().checked_add(duration).unwrap()) } } else { // FUTEX_WAIT uses a relative timestamp. if op & futex_realtime != 0 { Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) } else { - Time::Monotonic(this.machine.clock.get_time_relative(duration).unwrap()) + Time::Monotonic(this.machine.clock.now().checked_add(duration).unwrap()) } }) }; diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 446293e03cb..496985fd083 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -840,7 +840,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? { Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { - Time::Monotonic(this.machine.clock.get_time_absolute(duration).unwrap()) + Time::Monotonic(this.machine.clock.anchor().checked_add(duration).unwrap()) } else { throw_unsup_format!("unsupported clock id: {}", clock_id); }; |
