1use std::cell::Cell;
2use std::time::{Duration, Instant as StdInstant, SystemTime};
3
4use crate::MiriMachine;
5
6const NANOSECONDS_PER_BASIC_BLOCK: u128 = 5000;
12
13#[derive(Debug)]
15pub struct Instant {
16 kind: InstantKind,
17}
18
19#[derive(Debug)]
20enum InstantKind {
21 Host(StdInstant),
22 Virtual { nanoseconds: u128 },
23}
24
25impl Instant {
26 pub fn add_lossy(&self, duration: Duration) -> Instant {
28 match self.kind {
29 InstantKind::Host(instant) => {
30 let i = instant
32 .checked_add(duration)
33 .unwrap_or_else(|| instant.checked_add(Duration::from_secs(3600)).unwrap());
34 Instant { kind: InstantKind::Host(i) }
35 }
36 InstantKind::Virtual { nanoseconds } => {
37 let n = nanoseconds.saturating_add(duration.as_nanos());
38 Instant { kind: InstantKind::Virtual { nanoseconds: n } }
39 }
40 }
41 }
42
43 pub fn duration_since(&self, earlier: Instant) -> Duration {
44 match (&self.kind, earlier.kind) {
45 (InstantKind::Host(instant), InstantKind::Host(earlier)) =>
46 instant.duration_since(earlier),
47 (
48 InstantKind::Virtual { nanoseconds },
49 InstantKind::Virtual { nanoseconds: earlier },
50 ) => {
51 let duration = nanoseconds.saturating_sub(earlier);
52 Duration::from_nanos_u128(duration)
53 }
54 _ => panic!("all `Instant` must be of the same kind"),
55 }
56 }
57}
58
59#[derive(Debug)]
61pub struct MonotonicClock {
62 kind: MonotonicClockKind,
63}
64
65#[derive(Debug)]
66enum MonotonicClockKind {
67 Host {
68 epoch: StdInstant,
71 },
72 Virtual {
73 nanoseconds: Cell<u128>,
75 },
76}
77
78impl MonotonicClock {
79 pub fn new(communicate: bool) -> Self {
81 let kind = if communicate {
82 MonotonicClockKind::Host { epoch: StdInstant::now() }
83 } else {
84 MonotonicClockKind::Virtual { nanoseconds: 0.into() }
85 };
86
87 Self { kind }
88 }
89
90 pub fn tick(&self) {
92 match &self.kind {
93 MonotonicClockKind::Host { .. } => {
94 }
96 MonotonicClockKind::Virtual { nanoseconds } => {
97 nanoseconds.update(|x| x + NANOSECONDS_PER_BASIC_BLOCK);
98 }
99 }
100 }
101
102 pub fn sleep(&self, duration: Duration) {
104 match &self.kind {
105 MonotonicClockKind::Host { .. } => std::thread::sleep(duration),
106 MonotonicClockKind::Virtual { nanoseconds } => {
107 let nanos: u128 = duration.as_nanos();
109 nanoseconds.update(|x| {
110 x.checked_add(nanos)
111 .expect("Miri's virtual clock cannot represent an execution this long")
112 });
113 }
114 }
115 }
116
117 pub fn epoch(&self) -> Instant {
119 match &self.kind {
120 MonotonicClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) },
121 MonotonicClockKind::Virtual { .. } =>
122 Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
123 }
124 }
125
126 pub fn now(&self) -> Instant {
127 match &self.kind {
128 MonotonicClockKind::Host { .. } =>
129 Instant { kind: InstantKind::Host(StdInstant::now()) },
130 MonotonicClockKind::Virtual { nanoseconds } =>
131 Instant { kind: InstantKind::Virtual { nanoseconds: nanoseconds.get() } },
132 }
133 }
134}
135
136#[derive(Debug)]
138pub enum Deadline {
139 Monotonic(Instant),
140 RealTime(SystemTime),
141}
142
143impl From<Instant> for Deadline {
144 fn from(value: Instant) -> Self {
145 Deadline::Monotonic(value)
146 }
147}
148
149impl Deadline {
150 fn add_lossy(&self, duration: Duration) -> Self {
152 match self {
153 Deadline::Monotonic(i) => Deadline::Monotonic(i.add_lossy(duration)),
154 Deadline::RealTime(s) => {
155 Deadline::RealTime(
157 s.checked_add(duration)
158 .unwrap_or_else(|| s.checked_add(Duration::from_secs(3600)).unwrap()),
159 )
160 }
161 }
162 }
163}
164
165#[derive(Debug, Copy, Clone, PartialEq)]
167pub enum TimeoutClock {
168 Monotonic,
170 RealTime,
172}
173
174#[derive(Debug, Copy, Clone)]
176pub enum TimeoutStyle {
177 Relative,
179 Absolute,
182}
183
184impl MiriMachine<'_> {
185 pub fn timeout(
187 &self,
188 clock: TimeoutClock,
189 style: TimeoutStyle,
190 duration: Duration,
191 ) -> Deadline {
192 let zero = match clock {
194 TimeoutClock::RealTime => {
195 assert!(self.communicate(), "cannot have `RealTime` timeout with isolation");
196 Deadline::RealTime(match style {
197 TimeoutStyle::Absolute => SystemTime::UNIX_EPOCH,
198 TimeoutStyle::Relative => SystemTime::now(),
199 })
200 }
201 TimeoutClock::Monotonic =>
202 Deadline::Monotonic(match style {
203 TimeoutStyle::Absolute => self.monotonic_clock.epoch(),
204 TimeoutStyle::Relative => self.monotonic_clock.now(),
205 }),
206 };
207 zero.add_lossy(duration)
209 }
210}