about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/clock.rs131
-rw-r--r--src/concurrency/thread.rs16
-rw-r--r--src/lib.rs4
-rw-r--r--src/machine.rs2
-rw-r--r--src/shims/time.rs144
-rw-r--r--src/shims/unix/linux/sync.rs4
-rw-r--r--src/shims/unix/sync.rs2
7 files changed, 154 insertions, 149 deletions
diff --git a/src/clock.rs b/src/clock.rs
new file mode 100644
index 00000000000..faf2d7fda6c
--- /dev/null
+++ b/src/clock.rs
@@ -0,0 +1,131 @@
+use std::sync::atomic::AtomicU64;
+use std::time::{Duration, Instant as StdInstant};
+
+use rustc_data_structures::sync::Ordering;
+
+use crate::*;
+
+/// When using a virtual clock, this defines how many nanoseconds do we pretend
+/// are passing for each basic block.
+const NANOSECOND_PER_BASIC_BLOCK: u64 = 10;
+
+#[derive(Debug)]
+pub struct Instant {
+    kind: InstantKind,
+}
+
+#[derive(Debug)]
+enum InstantKind {
+    Host(StdInstant),
+    Virtual { nanoseconds: u64 },
+}
+
+/// A monotone clock used for `Instant` simulation.
+#[derive(Debug)]
+pub struct Clock {
+    kind: ClockKind,
+}
+
+#[derive(Debug)]
+enum ClockKind {
+    Host {
+        /// The "time anchor" for this machine's monotone clock.
+        time_anchor: StdInstant,
+    },
+    Virtual {
+        /// The "current virtual time".
+        nanoseconds: AtomicU64,
+    },
+}
+
+impl Clock {
+    /// 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 { time_anchor: StdInstant::now() }
+        } else {
+            ClockKind::Virtual { nanoseconds: 0.into() }
+        };
+
+        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 {
+            ClockKind::Host { .. } => {
+                // Time will pass without us doing anything.
+            }
+            ClockKind::Virtual { nanoseconds } => {
+                nanoseconds.fetch_add(NANOSECOND_PER_BASIC_BLOCK, Ordering::Relaxed);
+            }
+        }
+    }
+
+    /// Sleep for the desired duration.
+    pub fn sleep(&self, duration: Duration) {
+        match &self.kind {
+            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);
+            }
+        }
+    }
+
+    /// Compute `now + duration` relative to this clock.
+    pub fn get_time_relative(&self, duration: Duration) -> Option<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 } }),
+        }
+    }
+
+    /// 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> {
+        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!(),
+        }
+    }
+}
diff --git a/src/concurrency/thread.rs b/src/concurrency/thread.rs
index 8f1fabdddcf..b39a6716848 100644
--- a/src/concurrency/thread.rs
+++ b/src/concurrency/thread.rs
@@ -16,7 +16,6 @@ use rustc_target::spec::abi::Abi;
 
 use crate::concurrency::data_race;
 use crate::concurrency::sync::SynchronizationState;
-use crate::shims::time::{Clock, Instant};
 use crate::*;
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -188,6 +187,17 @@ pub enum Time {
     RealTime(SystemTime),
 }
 
+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::RealTime(time) =>
+                time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)),
+        }
+    }
+}
+
 /// Callbacks are used to implement timeouts. For example, waiting on a
 /// conditional variable with a timeout creates a callback that is called after
 /// the specified time and unblocks the thread. If another thread signals on the
@@ -489,7 +499,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
         for thread in self.threads.indices() {
             match self.timeout_callbacks.entry(thread) {
                 Entry::Occupied(entry) =>
-                    if clock.get_wait_time(&entry.get().call_time) == Duration::new(0, 0) {
+                    if entry.get().call_time.get_wait_time(clock) == Duration::new(0, 0) {
                         return Some((thread, entry.remove().callback));
                     },
                 Entry::Vacant(_) => {}
@@ -573,7 +583,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
         // at the time of the call".
         // <https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html>
         let potential_sleep_time =
-            self.timeout_callbacks.values().map(|info| clock.get_wait_time(&info.call_time)).min();
+            self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time(clock)).min();
         if potential_sleep_time == Some(Duration::new(0, 0)) {
             return Ok(SchedulingAction::ExecuteTimeoutCallback);
         }
diff --git a/src/lib.rs b/src/lib.rs
index 4fb6704165b..016ed01f4da 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,6 +51,7 @@ extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
 
+mod clock;
 mod concurrency;
 mod diagnostics;
 mod eval;
@@ -81,6 +82,7 @@ pub use crate::shims::time::EvalContextExt as _;
 pub use crate::shims::tls::{EvalContextExt as _, TlsData};
 pub use crate::shims::EvalContextExt as _;
 
+pub use crate::clock::{Clock, Instant};
 pub use crate::concurrency::{
     data_race::{
         AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd,
@@ -89,7 +91,7 @@ pub use crate::concurrency::{
     sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId},
     thread::{
         EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager,
-        ThreadState,
+        ThreadState, Time,
     },
 };
 pub use crate::diagnostics::{
diff --git a/src/machine.rs b/src/machine.rs
index 7a3b8732fca..4cfedd3bdf4 100644
--- a/src/machine.rs
+++ b/src/machine.rs
@@ -27,7 +27,7 @@ use rustc_target::spec::abi::Abi;
 
 use crate::{
     concurrency::{data_race, weak_memory},
-    shims::{time::Clock, unix::FileHandler},
+    shims::unix::FileHandler,
     *,
 };
 
diff --git a/src/shims/time.rs b/src/shims/time.rs
index fa01b7b1cae..46164e478f8 100644
--- a/src/shims/time.rs
+++ b/src/shims/time.rs
@@ -1,145 +1,7 @@
-use std::sync::atomic::AtomicU64;
-use std::time::{Duration, Instant as StdInstant, SystemTime};
+use std::time::{Duration, SystemTime};
 
-use rustc_data_structures::sync::Ordering;
-
-use crate::concurrency::thread::Time;
 use crate::*;
 
-/// When using a virtual clock, this defines how many nanoseconds do we pretend
-/// are passing for each basic block.
-const NANOSECOND_PER_BASIC_BLOCK: u64 = 10;
-
-#[derive(Debug)]
-pub struct Instant {
-    kind: InstantKind,
-}
-
-#[derive(Debug)]
-enum InstantKind {
-    Host(StdInstant),
-    Virtual { nanoseconds: u64 },
-}
-
-/// A monotone clock used for `Instant` simulation.
-#[derive(Debug)]
-pub struct Clock {
-    kind: ClockKind,
-}
-
-#[derive(Debug)]
-enum ClockKind {
-    Host {
-        /// The "time anchor" for this machine's monotone clock.
-        time_anchor: StdInstant,
-    },
-    Virtual {
-        /// The "current virtual time".
-        nanoseconds: AtomicU64,
-    },
-}
-
-impl Clock {
-    /// 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 { time_anchor: StdInstant::now() }
-        } else {
-            ClockKind::Virtual { nanoseconds: 0.into() }
-        };
-
-        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 {
-            ClockKind::Host { .. } => {
-                // Time will pass without us doing anything.
-            }
-            ClockKind::Virtual { nanoseconds } => {
-                nanoseconds.fetch_add(NANOSECOND_PER_BASIC_BLOCK, Ordering::Relaxed);
-            }
-        }
-    }
-
-    /// Sleep for the desired duration.
-    pub fn sleep(&self, duration: Duration) {
-        match &self.kind {
-            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);
-            }
-        }
-    }
-
-    /// Compute `now + duration` relative to this clock.
-    pub fn get_time_relative(&self, duration: Duration) -> Option<Time> {
-        match &self.kind {
-            ClockKind::Host { .. } =>
-                StdInstant::now()
-                    .checked_add(duration)
-                    .map(|instant| Time::Monotonic(Instant { kind: InstantKind::Host(instant) })),
-            ClockKind::Virtual { nanoseconds } =>
-                nanoseconds
-                    .load(Ordering::Relaxed)
-                    .checked_add(duration.as_nanos().try_into().unwrap())
-                    .map(|nanoseconds| {
-                        Time::Monotonic(Instant { kind: InstantKind::Virtual { nanoseconds } })
-                    }),
-        }
-    }
-
-    /// 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<Time> {
-        match &self.kind {
-            ClockKind::Host { time_anchor } =>
-                time_anchor
-                    .checked_add(duration)
-                    .map(|instant| Time::Monotonic(Instant { kind: InstantKind::Host(instant) })),
-            ClockKind::Virtual { .. } =>
-                Some(Time::Monotonic(Instant {
-                    kind: InstantKind::Virtual {
-                        nanoseconds: duration.as_nanos().try_into().unwrap(),
-                    },
-                })),
-        }
-    }
-
-    /// How long do we have to wait from now until the specified time?
-    pub fn get_wait_time(&self, time: &Time) -> Duration {
-        match time {
-            Time::Monotonic(instant) =>
-                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!(),
-                },
-            Time::RealTime(time) =>
-                time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)),
-        }
-    }
-}
-
 /// 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)
@@ -354,7 +216,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
 
         this.register_timeout_callback(
             active_thread,
-            timeout_time,
+            Time::Monotonic(timeout_time),
             Box::new(move |ecx| {
                 ecx.unblock_thread(active_thread);
                 Ok(())
@@ -380,7 +242,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
 
         this.register_timeout_callback(
             active_thread,
-            timeout_time,
+            Time::Monotonic(timeout_time),
             Box::new(move |ecx| {
                 ecx.unblock_thread(active_thread);
                 Ok(())
diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs
index 1c5be0438bf..b2c2fa14d52 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 {
-                        this.machine.clock.get_time_absolute(duration).unwrap()
+                        Time::Monotonic(this.machine.clock.get_time_absolute(duration).unwrap())
                     }
                 } else {
                     // FUTEX_WAIT uses a relative timestamp.
                     if op & futex_realtime != 0 {
                         Time::RealTime(SystemTime::now().checked_add(duration).unwrap())
                     } else {
-                        this.machine.clock.get_time_relative(duration).unwrap()
+                        Time::Monotonic(this.machine.clock.get_time_relative(duration).unwrap())
                     }
                 })
             };
diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs
index 4be418a3678..446293e03cb 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")? {
-            this.machine.clock.get_time_absolute(duration).unwrap()
+            Time::Monotonic(this.machine.clock.get_time_absolute(duration).unwrap())
         } else {
             throw_unsup_format!("unsupported clock id: {}", clock_id);
         };