]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/src/clock.rs
Rollup merge of #103084 - inquisitivecrystal:control-flow, r=scottmcm
[rust.git] / src / tools / miri / src / clock.rs
1 use std::sync::atomic::{AtomicU64, Ordering};
2 use std::time::{Duration, Instant as StdInstant};
3
4 /// When using a virtual clock, this defines how many nanoseconds we pretend are passing for each
5 /// basic block.
6 const NANOSECONDS_PER_BASIC_BLOCK: u64 = 10;
7
8 #[derive(Debug)]
9 pub struct Instant {
10     kind: InstantKind,
11 }
12
13 #[derive(Debug)]
14 enum InstantKind {
15     Host(StdInstant),
16     Virtual { nanoseconds: u64 },
17 }
18
19 impl Instant {
20     pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
21         match self.kind {
22             InstantKind::Host(instant) =>
23                 instant.checked_add(duration).map(|i| Instant { kind: InstantKind::Host(i) }),
24             InstantKind::Virtual { nanoseconds } =>
25                 u128::from(nanoseconds)
26                     .checked_add(duration.as_nanos())
27                     .and_then(|n| u64::try_from(n).ok())
28                     .map(|nanoseconds| Instant { kind: InstantKind::Virtual { nanoseconds } }),
29         }
30     }
31
32     pub fn duration_since(&self, earlier: Instant) -> Duration {
33         match (&self.kind, earlier.kind) {
34             (InstantKind::Host(instant), InstantKind::Host(earlier)) =>
35                 instant.duration_since(earlier),
36             (
37                 InstantKind::Virtual { nanoseconds },
38                 InstantKind::Virtual { nanoseconds: earlier },
39             ) => Duration::from_nanos(nanoseconds.saturating_sub(earlier)),
40             _ => panic!("all `Instant` must be of the same kind"),
41         }
42     }
43 }
44
45 /// A monotone clock used for `Instant` simulation.
46 #[derive(Debug)]
47 pub struct Clock {
48     kind: ClockKind,
49 }
50
51 #[derive(Debug)]
52 enum ClockKind {
53     Host {
54         /// The "time anchor" for this machine's monotone clock.
55         time_anchor: StdInstant,
56     },
57     Virtual {
58         /// The "current virtual time".
59         nanoseconds: AtomicU64,
60     },
61 }
62
63 impl Clock {
64     /// Create a new clock based on the availability of communication with the host.
65     pub fn new(communicate: bool) -> Self {
66         let kind = if communicate {
67             ClockKind::Host { time_anchor: StdInstant::now() }
68         } else {
69             ClockKind::Virtual { nanoseconds: 0.into() }
70         };
71
72         Self { kind }
73     }
74
75     /// Let the time pass for a small interval.
76     pub fn tick(&self) {
77         match &self.kind {
78             ClockKind::Host { .. } => {
79                 // Time will pass without us doing anything.
80             }
81             ClockKind::Virtual { nanoseconds } => {
82                 nanoseconds.fetch_add(NANOSECONDS_PER_BASIC_BLOCK, Ordering::SeqCst);
83             }
84         }
85     }
86
87     /// Sleep for the desired duration.
88     pub fn sleep(&self, duration: Duration) {
89         match &self.kind {
90             ClockKind::Host { .. } => std::thread::sleep(duration),
91             ClockKind::Virtual { nanoseconds } => {
92                 // Just pretend that we have slept for some time.
93                 nanoseconds.fetch_add(duration.as_nanos().try_into().unwrap(), Ordering::SeqCst);
94             }
95         }
96     }
97
98     /// Return the `anchor` instant, to convert between monotone instants and durations relative to the anchor.
99     pub fn anchor(&self) -> Instant {
100         match &self.kind {
101             ClockKind::Host { time_anchor } => Instant { kind: InstantKind::Host(*time_anchor) },
102             ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
103         }
104     }
105
106     pub fn now(&self) -> Instant {
107         match &self.kind {
108             ClockKind::Host { .. } => Instant { kind: InstantKind::Host(StdInstant::now()) },
109             ClockKind::Virtual { nanoseconds } =>
110                 Instant {
111                     kind: InstantKind::Virtual { nanoseconds: nanoseconds.load(Ordering::SeqCst) },
112                 },
113         }
114     }
115 }