]>
Commit | Line | Data |
---|---|---|
532ac7d7 XL |
1 | use crate::cmp::Ordering; |
2 | use crate::time::Duration; | |
3 | ||
ff7c6d11 | 4 | use core::hash::{Hash, Hasher}; |
a7813a04 | 5 | |
92a42be0 | 6 | pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; |
532ac7d7 | 7 | use crate::convert::TryInto; |
85aaf69f | 8 | |
d9579d0f AL |
9 | const NSEC_PER_SEC: u64 = 1_000_000_000; |
10 | ||
a7813a04 XL |
11 | #[derive(Copy, Clone)] |
12 | struct Timespec { | |
13 | t: libc::timespec, | |
14 | } | |
15 | ||
16 | impl Timespec { | |
0731742a | 17 | const fn zero() -> Timespec { |
dfeec247 | 18 | Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } } |
0731742a XL |
19 | } |
20 | ||
a7813a04 XL |
21 | fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { |
22 | if self >= other { | |
23 | Ok(if self.t.tv_nsec >= other.t.tv_nsec { | |
dfeec247 XL |
24 | Duration::new( |
25 | (self.t.tv_sec - other.t.tv_sec) as u64, | |
26 | (self.t.tv_nsec - other.t.tv_nsec) as u32, | |
27 | ) | |
a7813a04 | 28 | } else { |
dfeec247 XL |
29 | Duration::new( |
30 | (self.t.tv_sec - 1 - other.t.tv_sec) as u64, | |
31 | self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32, | |
32 | ) | |
a7813a04 XL |
33 | }) |
34 | } else { | |
35 | match other.sub_timespec(self) { | |
36 | Ok(d) => Err(d), | |
37 | Err(d) => Ok(d), | |
38 | } | |
39 | } | |
40 | } | |
41 | ||
a1dfa0c6 | 42 | fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> { |
ea8adc8c XL |
43 | let mut secs = other |
44 | .as_secs() | |
45 | .try_into() // <- target type would be `libc::time_t` | |
46 | .ok() | |
a1dfa0c6 | 47 | .and_then(|secs| self.t.tv_sec.checked_add(secs))?; |
a7813a04 XL |
48 | |
49 | // Nano calculations can't overflow because nanos are <1B which fit | |
50 | // in a u32. | |
51 | let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; | |
52 | if nsec >= NSEC_PER_SEC as u32 { | |
53 | nsec -= NSEC_PER_SEC as u32; | |
a1dfa0c6 | 54 | secs = secs.checked_add(1)?; |
a7813a04 | 55 | } |
dfeec247 | 56 | Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } }) |
a7813a04 XL |
57 | } |
58 | ||
0731742a | 59 | fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> { |
ea8adc8c XL |
60 | let mut secs = other |
61 | .as_secs() | |
62 | .try_into() // <- target type would be `libc::time_t` | |
63 | .ok() | |
0731742a | 64 | .and_then(|secs| self.t.tv_sec.checked_sub(secs))?; |
a7813a04 XL |
65 | |
66 | // Similar to above, nanos can't overflow. | |
67 | let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; | |
68 | if nsec < 0 { | |
69 | nsec += NSEC_PER_SEC as i32; | |
0731742a | 70 | secs = secs.checked_sub(1)?; |
a7813a04 | 71 | } |
dfeec247 | 72 | Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } }) |
a7813a04 XL |
73 | } |
74 | } | |
75 | ||
76 | impl PartialEq for Timespec { | |
77 | fn eq(&self, other: &Timespec) -> bool { | |
78 | self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec | |
79 | } | |
80 | } | |
81 | ||
82 | impl Eq for Timespec {} | |
83 | ||
84 | impl PartialOrd for Timespec { | |
85 | fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> { | |
86 | Some(self.cmp(other)) | |
87 | } | |
88 | } | |
89 | ||
90 | impl Ord for Timespec { | |
91 | fn cmp(&self, other: &Timespec) -> Ordering { | |
92 | let me = (self.t.tv_sec, self.t.tv_nsec); | |
93 | let other = (other.t.tv_sec, other.t.tv_nsec); | |
94 | me.cmp(&other) | |
95 | } | |
96 | } | |
97 | ||
ff7c6d11 | 98 | impl Hash for Timespec { |
dfeec247 | 99 | fn hash<H: Hasher>(&self, state: &mut H) { |
ff7c6d11 XL |
100 | self.t.tv_sec.hash(state); |
101 | self.t.tv_nsec.hash(state); | |
102 | } | |
103 | } | |
104 | ||
85aaf69f SL |
105 | #[cfg(any(target_os = "macos", target_os = "ios"))] |
106 | mod inner { | |
532ac7d7 XL |
107 | use crate::fmt; |
108 | use crate::mem; | |
109 | use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; | |
110 | use crate::sys::cvt; | |
111 | use crate::sys_common::mul_div_u64; | |
112 | use crate::time::Duration; | |
85aaf69f | 113 | |
a7813a04 | 114 | use super::Timespec; |
dfeec247 | 115 | use super::NSEC_PER_SEC; |
92a42be0 | 116 | |
ff7c6d11 | 117 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] |
92a42be0 | 118 | pub struct Instant { |
dfeec247 | 119 | t: u64, |
85aaf69f SL |
120 | } |
121 | ||
ff7c6d11 | 122 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
92a42be0 | 123 | pub struct SystemTime { |
a7813a04 | 124 | t: Timespec, |
85aaf69f SL |
125 | } |
126 | ||
dfeec247 | 127 | pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() }; |
92a42be0 | 128 | |
416331ca XL |
129 | #[repr(C)] |
130 | #[derive(Copy, Clone)] | |
131 | struct mach_timebase_info { | |
132 | numer: u32, | |
133 | denom: u32, | |
134 | } | |
135 | type mach_timebase_info_t = *mut mach_timebase_info; | |
136 | type kern_return_t = libc::c_int; | |
137 | ||
92a42be0 SL |
138 | impl Instant { |
139 | pub fn now() -> Instant { | |
416331ca XL |
140 | extern "C" { |
141 | fn mach_absolute_time() -> u64; | |
142 | } | |
143 | Instant { t: unsafe { mach_absolute_time() } } | |
92a42be0 SL |
144 | } |
145 | ||
0731742a XL |
146 | pub const fn zero() -> Instant { |
147 | Instant { t: 0 } | |
148 | } | |
149 | ||
150 | pub fn actually_monotonic() -> bool { | |
151 | true | |
152 | } | |
153 | ||
532ac7d7 XL |
154 | pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> { |
155 | let diff = self.t.checked_sub(other.t)?; | |
92a42be0 | 156 | let info = info(); |
92a42be0 | 157 | let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64); |
532ac7d7 | 158 | Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)) |
92a42be0 SL |
159 | } |
160 | ||
0731742a | 161 | pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> { |
dfeec247 | 162 | Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? }) |
92a42be0 SL |
163 | } |
164 | ||
0731742a | 165 | pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> { |
dfeec247 | 166 | Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? }) |
85aaf69f | 167 | } |
85aaf69f SL |
168 | } |
169 | ||
92a42be0 SL |
170 | impl SystemTime { |
171 | pub fn now() -> SystemTime { | |
532ac7d7 | 172 | use crate::ptr; |
5bcae85e | 173 | |
dfeec247 XL |
174 | let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 }; |
175 | cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap(); | |
176 | return SystemTime::from(s); | |
92a42be0 SL |
177 | } |
178 | ||
dfeec247 | 179 | pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { |
a7813a04 | 180 | self.t.sub_timespec(&other.t) |
92a42be0 SL |
181 | } |
182 | ||
a1dfa0c6 | 183 | pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { |
0731742a | 184 | Some(SystemTime { t: self.t.checked_add_duration(other)? }) |
a1dfa0c6 XL |
185 | } |
186 | ||
0731742a XL |
187 | pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { |
188 | Some(SystemTime { t: self.t.checked_sub_duration(other)? }) | |
92a42be0 SL |
189 | } |
190 | } | |
191 | ||
7453a54e SL |
192 | impl From<libc::timeval> for SystemTime { |
193 | fn from(t: libc::timeval) -> SystemTime { | |
a7813a04 XL |
194 | SystemTime::from(libc::timespec { |
195 | tv_sec: t.tv_sec, | |
196 | tv_nsec: (t.tv_usec * 1000) as libc::c_long, | |
197 | }) | |
92a42be0 SL |
198 | } |
199 | } | |
200 | ||
a7813a04 XL |
201 | impl From<libc::timespec> for SystemTime { |
202 | fn from(t: libc::timespec) -> SystemTime { | |
a1dfa0c6 | 203 | SystemTime { t: Timespec { t } } |
92a42be0 SL |
204 | } |
205 | } | |
206 | ||
207 | impl fmt::Debug for SystemTime { | |
532ac7d7 | 208 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
92a42be0 | 209 | f.debug_struct("SystemTime") |
dfeec247 XL |
210 | .field("tv_sec", &self.t.t.tv_sec) |
211 | .field("tv_nsec", &self.t.t.tv_nsec) | |
212 | .finish() | |
92a42be0 SL |
213 | } |
214 | } | |
215 | ||
0731742a | 216 | fn checked_dur2intervals(dur: &Duration) -> Option<u64> { |
dfeec247 XL |
217 | let nanos = |
218 | dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?; | |
92a42be0 | 219 | let info = info(); |
0731742a | 220 | Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64)) |
92a42be0 SL |
221 | } |
222 | ||
416331ca | 223 | fn info() -> mach_timebase_info { |
dfeec247 | 224 | static mut INFO: mach_timebase_info = mach_timebase_info { numer: 0, denom: 0 }; |
532ac7d7 | 225 | static STATE: AtomicUsize = AtomicUsize::new(0); |
85aaf69f SL |
226 | |
227 | unsafe { | |
532ac7d7 XL |
228 | // If a previous thread has filled in this global state, use that. |
229 | if STATE.load(SeqCst) == 2 { | |
230 | return INFO; | |
231 | } | |
232 | ||
233 | // ... otherwise learn for ourselves ... | |
234 | let mut info = mem::zeroed(); | |
416331ca | 235 | extern "C" { |
dfeec247 | 236 | fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t; |
416331ca XL |
237 | } |
238 | ||
239 | mach_timebase_info(&mut info); | |
532ac7d7 XL |
240 | |
241 | // ... and attempt to be the one thread that stores it globally for | |
242 | // all other threads | |
243 | if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() { | |
244 | INFO = info; | |
245 | STATE.store(2, SeqCst); | |
246 | } | |
247 | return info; | |
85aaf69f SL |
248 | } |
249 | } | |
85aaf69f SL |
250 | } |
251 | ||
252 | #[cfg(not(any(target_os = "macos", target_os = "ios")))] | |
253 | mod inner { | |
532ac7d7 XL |
254 | use crate::fmt; |
255 | use crate::sys::cvt; | |
256 | use crate::time::Duration; | |
85aaf69f | 257 | |
a7813a04 | 258 | use super::Timespec; |
85aaf69f | 259 | |
ff7c6d11 | 260 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
92a42be0 SL |
261 | pub struct Instant { |
262 | t: Timespec, | |
263 | } | |
264 | ||
ff7c6d11 | 265 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
92a42be0 SL |
266 | pub struct SystemTime { |
267 | t: Timespec, | |
268 | } | |
269 | ||
dfeec247 | 270 | pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() }; |
85aaf69f | 271 | |
92a42be0 SL |
272 | impl Instant { |
273 | pub fn now() -> Instant { | |
a7813a04 | 274 | Instant { t: now(libc::CLOCK_MONOTONIC) } |
92a42be0 SL |
275 | } |
276 | ||
0731742a | 277 | pub const fn zero() -> Instant { |
dfeec247 | 278 | Instant { t: Timespec::zero() } |
0731742a XL |
279 | } |
280 | ||
281 | pub fn actually_monotonic() -> bool { | |
dfeec247 XL |
282 | (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64")) |
283 | || (cfg!(target_os = "linux") && cfg!(target_arch = "x86")) | |
284 | || cfg!(target_os = "fuchsia") | |
0731742a XL |
285 | } |
286 | ||
532ac7d7 XL |
287 | pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> { |
288 | self.t.sub_timespec(&other.t).ok() | |
92a42be0 SL |
289 | } |
290 | ||
0731742a XL |
291 | pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> { |
292 | Some(Instant { t: self.t.checked_add_duration(other)? }) | |
92a42be0 SL |
293 | } |
294 | ||
0731742a XL |
295 | pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> { |
296 | Some(Instant { t: self.t.checked_sub_duration(other)? }) | |
92a42be0 SL |
297 | } |
298 | } | |
299 | ||
300 | impl fmt::Debug for Instant { | |
532ac7d7 | 301 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
92a42be0 | 302 | f.debug_struct("Instant") |
dfeec247 XL |
303 | .field("tv_sec", &self.t.t.tv_sec) |
304 | .field("tv_nsec", &self.t.t.tv_nsec) | |
305 | .finish() | |
92a42be0 SL |
306 | } |
307 | } | |
308 | ||
309 | impl SystemTime { | |
310 | pub fn now() -> SystemTime { | |
a7813a04 | 311 | SystemTime { t: now(libc::CLOCK_REALTIME) } |
92a42be0 SL |
312 | } |
313 | ||
dfeec247 | 314 | pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { |
92a42be0 SL |
315 | self.t.sub_timespec(&other.t) |
316 | } | |
317 | ||
a1dfa0c6 | 318 | pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { |
0731742a | 319 | Some(SystemTime { t: self.t.checked_add_duration(other)? }) |
a1dfa0c6 XL |
320 | } |
321 | ||
0731742a XL |
322 | pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { |
323 | Some(SystemTime { t: self.t.checked_sub_duration(other)? }) | |
92a42be0 SL |
324 | } |
325 | } | |
b039eaaf | 326 | |
7453a54e SL |
327 | impl From<libc::timespec> for SystemTime { |
328 | fn from(t: libc::timespec) -> SystemTime { | |
a1dfa0c6 | 329 | SystemTime { t: Timespec { t } } |
7453a54e SL |
330 | } |
331 | } | |
332 | ||
92a42be0 | 333 | impl fmt::Debug for SystemTime { |
532ac7d7 | 334 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
92a42be0 | 335 | f.debug_struct("SystemTime") |
dfeec247 XL |
336 | .field("tv_sec", &self.t.t.tv_sec) |
337 | .field("tv_nsec", &self.t.t.tv_nsec) | |
338 | .finish() | |
92a42be0 | 339 | } |
85aaf69f SL |
340 | } |
341 | ||
e74abb32 | 342 | #[cfg(not(target_os = "dragonfly"))] |
54a0048b | 343 | pub type clock_t = libc::c_int; |
e74abb32 | 344 | #[cfg(target_os = "dragonfly")] |
54a0048b SL |
345 | pub type clock_t = libc::c_ulong; |
346 | ||
a7813a04 | 347 | fn now(clock: clock_t) -> Timespec { |
dfeec247 XL |
348 | let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }; |
349 | cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap(); | |
a7813a04 | 350 | t |
85aaf69f SL |
351 | } |
352 | } |