shadow_shim_helper_rs/
emulated_time.rs
1use std::sync::atomic::{AtomicU64, Ordering};
6
7use vasi::VirtualAddressSpaceIndependent;
8
9use crate::simulation_time::{self, CSimulationTime, SimulationTime};
10
11#[derive(
15 Copy, Clone, Eq, PartialEq, Debug, PartialOrd, Ord, Hash, VirtualAddressSpaceIndependent,
16)]
17#[repr(C)]
18pub struct EmulatedTime(CEmulatedTime);
19
20pub type CEmulatedTime = u64;
26
27pub const SIMULATION_START_SEC: u64 = 946684800u64;
29pub const EMUTIME_INVALID: CEmulatedTime = u64::MAX;
30pub const EMUTIME_MAX: CEmulatedTime = u64::MAX - 1;
31pub const EMUTIME_MIN: CEmulatedTime = 0u64;
32
33pub const EMUTIME_SIMULATION_START: CEmulatedTime = 946684800u64 * 1_000_000_000u64;
38const _: () =
39 assert!(EMUTIME_SIMULATION_START == SIMULATION_START_SEC * simulation_time::SIMTIME_ONE_SECOND);
40
41pub const EMUTIME_UNIX_EPOCH: CEmulatedTime = 0u64;
43
44impl EmulatedTime {
45 pub const SIMULATION_START: Self = Self(EMUTIME_SIMULATION_START);
47 pub const UNIX_EPOCH: Self = Self(0);
49
50 pub const MAX: Self = Self(EMUTIME_MAX);
51 pub const MIN: Self = Self(0);
52
53 pub const fn from_c_emutime(val: CEmulatedTime) -> Option<Self> {
55 if val == EMUTIME_INVALID || val > EMUTIME_MAX {
56 None
57 } else {
58 Some(Self(val))
59 }
60 }
61
62 pub const fn to_c_emutime(val: Option<Self>) -> CEmulatedTime {
64 match val {
65 Some(v) => v.0,
66 None => EMUTIME_INVALID,
67 }
68 }
69
70 pub fn from_abs_simtime(val: SimulationTime) -> Self {
72 Self::SIMULATION_START + val
73 }
74
75 pub fn to_abs_simtime(self) -> SimulationTime {
77 self.duration_since(&Self::SIMULATION_START)
78 }
79
80 pub fn duration_since(&self, earlier: &EmulatedTime) -> SimulationTime {
83 self.checked_duration_since(earlier).unwrap()
84 }
85
86 pub fn checked_duration_since(&self, earlier: &EmulatedTime) -> Option<SimulationTime> {
88 let d = self.0.checked_sub(earlier.0)?;
89 SimulationTime::from_c_simtime(d)
90 }
91
92 pub fn saturating_duration_since(&self, earlier: &EmulatedTime) -> SimulationTime {
94 self.checked_duration_since(earlier)
95 .unwrap_or(SimulationTime::ZERO)
96 }
97
98 pub fn checked_add(&self, duration: SimulationTime) -> Option<EmulatedTime> {
99 EmulatedTime::from_c_emutime(self.0.checked_add(CSimulationTime::from(duration))?)
100 }
101
102 pub fn checked_sub(&self, duration: SimulationTime) -> Option<EmulatedTime> {
103 EmulatedTime::from_c_emutime(self.0.checked_sub(CSimulationTime::from(duration))?)
104 }
105
106 pub fn saturating_add(&self, duration: SimulationTime) -> EmulatedTime {
107 match self.checked_add(duration) {
108 Some(later) => later,
109 None => EmulatedTime::MAX,
110 }
111 }
112
113 pub fn saturating_sub(&self, duration: SimulationTime) -> EmulatedTime {
114 match self.checked_sub(duration) {
115 Some(earlier) => earlier,
116 None => EmulatedTime::SIMULATION_START,
117 }
118 }
119}
120
121impl std::ops::Add<SimulationTime> for EmulatedTime {
122 type Output = EmulatedTime;
123
124 fn add(self, other: SimulationTime) -> Self {
125 self.checked_add(other).unwrap()
126 }
127}
128
129impl std::ops::AddAssign<SimulationTime> for EmulatedTime {
130 fn add_assign(&mut self, rhs: SimulationTime) {
131 *self = *self + rhs;
132 }
133}
134
135impl std::ops::Sub<SimulationTime> for EmulatedTime {
136 type Output = EmulatedTime;
137
138 fn sub(self, other: SimulationTime) -> Self {
139 self.checked_sub(other).unwrap()
140 }
141}
142
143impl std::ops::Sub<EmulatedTime> for EmulatedTime {
144 type Output = SimulationTime;
145
146 fn sub(self, other: EmulatedTime) -> Self::Output {
147 self.duration_since(&other)
148 }
149}
150
151impl std::ops::SubAssign<SimulationTime> for EmulatedTime {
152 fn sub_assign(&mut self, rhs: SimulationTime) {
153 *self = self.checked_sub(rhs).unwrap();
154 }
155}
156
157impl tcp::util::time::Instant for EmulatedTime {
158 type Duration = SimulationTime;
159
160 #[inline]
161 fn duration_since(&self, earlier: Self) -> Self::Duration {
162 self.duration_since(&earlier)
163 }
164
165 #[inline]
166 fn saturating_duration_since(&self, earlier: Self) -> Self::Duration {
167 self.saturating_duration_since(&earlier)
168 }
169
170 #[inline]
171 fn checked_duration_since(&self, earlier: Self) -> Option<Self::Duration> {
172 self.checked_duration_since(&earlier)
173 }
174
175 #[inline]
176 fn checked_add(&self, duration: Self::Duration) -> Option<Self> {
177 self.checked_add(duration)
178 }
179
180 #[inline]
181 fn checked_sub(&self, duration: Self::Duration) -> Option<Self> {
182 self.checked_sub(duration)
183 }
184}
185
186pub mod export {
187 use super::*;
188
189 #[unsafe(no_mangle)]
190 pub extern "C-unwind" fn emutime_add_simtime(
191 lhs: CEmulatedTime,
192 rhs: CSimulationTime,
193 ) -> CEmulatedTime {
194 let Some(lhs) = EmulatedTime::from_c_emutime(lhs) else {
195 return EmulatedTime::to_c_emutime(None);
196 };
197 let Some(rhs) = SimulationTime::from_c_simtime(rhs) else {
198 return EmulatedTime::to_c_emutime(None);
199 };
200 let sum = lhs.checked_add(rhs);
201 EmulatedTime::to_c_emutime(sum)
202 }
203
204 #[unsafe(no_mangle)]
205 pub extern "C-unwind" fn emutime_sub_emutime(
206 lhs: CEmulatedTime,
207 rhs: CEmulatedTime,
208 ) -> CSimulationTime {
209 let Some(lhs) = EmulatedTime::from_c_emutime(lhs) else {
210 return EmulatedTime::to_c_emutime(None);
211 };
212 let Some(rhs) = EmulatedTime::from_c_emutime(rhs) else {
213 return EmulatedTime::to_c_emutime(None);
214 };
215 let diff = lhs.checked_duration_since(&rhs);
216 SimulationTime::to_c_simtime(diff)
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223 use crate::simulation_time;
224
225 #[test]
226 fn test_from_emu_time() {
227 let emu_time =
228 5 * simulation_time::SIMTIME_ONE_MINUTE + 7 * simulation_time::SIMTIME_ONE_MILLISECOND;
229 let rust_time = EmulatedTime::from_c_emutime(emu_time).unwrap();
230
231 assert_eq!(
232 rust_time
233 .duration_since(&EmulatedTime::UNIX_EPOCH)
234 .as_secs(),
235 5 * 60
236 );
237 assert_eq!(
238 rust_time
239 .duration_since(&EmulatedTime::UNIX_EPOCH)
240 .as_millis(),
241 5 * 60 * 1_000 + 7
242 );
243 }
244
245 #[test]
246 fn test_to_emu_time() {
247 let rust_time = EmulatedTime::UNIX_EPOCH
248 + SimulationTime::SECOND * 60 * 5
249 + SimulationTime::MILLISECOND * 7;
250 let sim_time =
251 5 * simulation_time::SIMTIME_ONE_MINUTE + 7 * simulation_time::SIMTIME_ONE_MILLISECOND;
252
253 assert_eq!(EmulatedTime::to_c_emutime(Some(rust_time)), sim_time);
254 assert_eq!(EmulatedTime::to_c_emutime(None), EMUTIME_INVALID);
255 }
256
257 #[test]
258 fn test_from_abs_simtime() {
259 assert_eq!(
260 EmulatedTime::from_abs_simtime(SimulationTime::ZERO),
261 EmulatedTime::SIMULATION_START
262 );
263
264 assert_eq!(
265 EmulatedTime::from_abs_simtime(SimulationTime::SECOND),
266 EmulatedTime::SIMULATION_START + SimulationTime::SECOND
267 );
268 }
269
270 #[test]
271 fn test_to_abs_simtime() {
272 assert_eq!(
273 EmulatedTime::SIMULATION_START.to_abs_simtime(),
274 SimulationTime::ZERO
275 );
276
277 assert_eq!(
278 (EmulatedTime::SIMULATION_START + SimulationTime::SECOND).to_abs_simtime(),
279 SimulationTime::SECOND
280 );
281 }
282}
283
284#[derive(VirtualAddressSpaceIndependent)]
285#[repr(C)]
286pub struct AtomicEmulatedTime(AtomicU64);
287
288impl AtomicEmulatedTime {
289 pub fn new(t: EmulatedTime) -> Self {
290 Self(AtomicU64::new(t.0))
291 }
292
293 pub fn load(&self, order: Ordering) -> EmulatedTime {
294 EmulatedTime(self.0.load(order))
295 }
296
297 pub fn store(&self, val: EmulatedTime, order: Ordering) {
298 self.0.store(val.0, order)
299 }
300}