1use std::cell::Cell;
2use std::time::{Duration, Instant as StdInstant};
3
4const NANOSECONDS_PER_BASIC_BLOCK: u128 = 5000;
10
11#[derive(Debug)]
12pub struct Instant {
13 kind: InstantKind,
14}
15
16#[derive(Debug)]
17enum InstantKind {
18 Host(StdInstant),
19 Virtual { nanoseconds: u128 },
20}
21
22impl Instant {
23 pub fn add_lossy(&self, duration: Duration) -> Instant {
25 match self.kind {
26 InstantKind::Host(instant) => {
27 let i = instant
29 .checked_add(duration)
30 .unwrap_or_else(|| instant.checked_add(Duration::from_secs(3600)).unwrap());
31 Instant { kind: InstantKind::Host(i) }
32 }
33 InstantKind::Virtual { nanoseconds } => {
34 let n = nanoseconds.saturating_add(duration.as_nanos());
35 Instant { kind: InstantKind::Virtual { nanoseconds: n } }
36 }
37 }
38 }
39
40 pub fn duration_since(&self, earlier: Instant) -> Duration {
41 match (&self.kind, earlier.kind) {
42 (InstantKind::Host(instant), InstantKind::Host(earlier)) =>
43 instant.duration_since(earlier),
44 (
45 InstantKind::Virtual { nanoseconds },
46 InstantKind::Virtual { nanoseconds: earlier },
47 ) => {
48 let duration = nanoseconds.saturating_sub(earlier);
49 cfg_select! {
50 bootstrap => {
51 let seconds = u64::try_from(duration / 1_000_000_000).unwrap_or(u64::MAX);
56 let nanosecond = u32::try_from(duration.wrapping_rem(1_000_000_000)).unwrap();
58 Duration::new(seconds, nanosecond)
59 }
60 _ => {
61 Duration::from_nanos_u128(duration)
62 }
63 }
64 }
65 _ => panic!("all `Instant` must be of the same kind"),
66 }
67 }
68}
69
70#[derive(Debug)]
72pub struct MonotonicClock {
73 kind: MonotonicClockKind,
74}
75
76#[derive(Debug)]
77enum MonotonicClockKind {
78 Host {
79 epoch: StdInstant,
82 },
83 Virtual {
84 nanoseconds: Cell<u128>,
86 },
87}
88
89impl MonotonicClock {
90 pub fn new(communicate: bool) -> Self {
92 let kind = if communicate {
93 MonotonicClockKind::Host { epoch: StdInstant::now() }
94 } else {
95 MonotonicClockKind::Virtual { nanoseconds: 0.into() }
96 };
97
98 Self { kind }
99 }
100
101 pub fn tick(&self) {
103 match &self.kind {
104 MonotonicClockKind::Host { .. } => {
105 }
107 MonotonicClockKind::Virtual { nanoseconds } => {
108 nanoseconds.update(|x| x + NANOSECONDS_PER_BASIC_BLOCK);
109 }
110 }
111 }
112
113 pub fn sleep(&self, duration: Duration) {
115 match &self.kind {
116 MonotonicClockKind::Host { .. } => std::thread::sleep(duration),
117 MonotonicClockKind::Virtual { nanoseconds } => {
118 let nanos: u128 = duration.as_nanos();
120 nanoseconds.update(|x| {
121 x.checked_add(nanos)
122 .expect("Miri's virtual clock cannot represent an execution this long")
123 });
124 }
125 }
126 }
127
128 pub fn epoch(&self) -> Instant {
130 match &self.kind {
131 MonotonicClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) },
132 MonotonicClockKind::Virtual { .. } =>
133 Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
134 }
135 }
136
137 pub fn now(&self) -> Instant {
138 match &self.kind {
139 MonotonicClockKind::Host { .. } =>
140 Instant { kind: InstantKind::Host(StdInstant::now()) },
141 MonotonicClockKind::Virtual { nanoseconds } =>
142 Instant { kind: InstantKind::Virtual { nanoseconds: nanoseconds.get() } },
143 }
144 }
145}