]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/unix/time.rs
New upstream version 1.43.0+dfsg1
[rustc.git] / src / libstd / sys / unix / time.rs
CommitLineData
532ac7d7
XL
1use crate::cmp::Ordering;
2use crate::time::Duration;
3
ff7c6d11 4use core::hash::{Hash, Hasher};
a7813a04 5
92a42be0 6pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
532ac7d7 7use crate::convert::TryInto;
85aaf69f 8
d9579d0f
AL
9const NSEC_PER_SEC: u64 = 1_000_000_000;
10
a7813a04
XL
11#[derive(Copy, Clone)]
12struct Timespec {
13 t: libc::timespec,
14}
15
16impl 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
76impl 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
82impl Eq for Timespec {}
83
84impl PartialOrd for Timespec {
85 fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
86 Some(self.cmp(other))
87 }
88}
89
90impl 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 98impl 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"))]
106mod 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")))]
253mod 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}