]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
a7813a04 | 11 | use cmp::Ordering; |
a7813a04 | 12 | use libc; |
5bcae85e | 13 | use time::Duration; |
ff7c6d11 | 14 | use core::hash::{Hash, Hasher}; |
a7813a04 | 15 | |
92a42be0 | 16 | pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; |
ea8adc8c | 17 | use convert::TryInto; |
85aaf69f | 18 | |
d9579d0f AL |
19 | const NSEC_PER_SEC: u64 = 1_000_000_000; |
20 | ||
a7813a04 XL |
21 | #[derive(Copy, Clone)] |
22 | struct Timespec { | |
23 | t: libc::timespec, | |
24 | } | |
25 | ||
26 | impl Timespec { | |
27 | fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { | |
28 | if self >= other { | |
29 | Ok(if self.t.tv_nsec >= other.t.tv_nsec { | |
30 | Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, | |
31 | (self.t.tv_nsec - other.t.tv_nsec) as u32) | |
32 | } else { | |
33 | Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, | |
34 | self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - | |
35 | other.t.tv_nsec as u32) | |
36 | }) | |
37 | } else { | |
38 | match other.sub_timespec(self) { | |
39 | Ok(d) => Err(d), | |
40 | Err(d) => Ok(d), | |
41 | } | |
42 | } | |
43 | } | |
44 | ||
45 | fn add_duration(&self, other: &Duration) -> Timespec { | |
ea8adc8c XL |
46 | let mut secs = other |
47 | .as_secs() | |
48 | .try_into() // <- target type would be `libc::time_t` | |
49 | .ok() | |
50 | .and_then(|secs| self.t.tv_sec.checked_add(secs)) | |
51 | .expect("overflow when adding duration to time"); | |
a7813a04 XL |
52 | |
53 | // Nano calculations can't overflow because nanos are <1B which fit | |
54 | // in a u32. | |
55 | let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; | |
56 | if nsec >= NSEC_PER_SEC as u32 { | |
57 | nsec -= NSEC_PER_SEC as u32; | |
58 | secs = secs.checked_add(1).expect("overflow when adding \ | |
59 | duration to time"); | |
60 | } | |
61 | Timespec { | |
62 | t: libc::timespec { | |
ea8adc8c | 63 | tv_sec: secs, |
abe05a73 | 64 | tv_nsec: nsec as _, |
a7813a04 XL |
65 | }, |
66 | } | |
67 | } | |
68 | ||
69 | fn sub_duration(&self, other: &Duration) -> Timespec { | |
ea8adc8c XL |
70 | let mut secs = other |
71 | .as_secs() | |
72 | .try_into() // <- target type would be `libc::time_t` | |
73 | .ok() | |
74 | .and_then(|secs| self.t.tv_sec.checked_sub(secs)) | |
75 | .expect("overflow when subtracting duration from time"); | |
a7813a04 XL |
76 | |
77 | // Similar to above, nanos can't overflow. | |
78 | let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; | |
79 | if nsec < 0 { | |
80 | nsec += NSEC_PER_SEC as i32; | |
81 | secs = secs.checked_sub(1).expect("overflow when subtracting \ | |
82 | duration from time"); | |
83 | } | |
84 | Timespec { | |
85 | t: libc::timespec { | |
ea8adc8c | 86 | tv_sec: secs, |
abe05a73 | 87 | tv_nsec: nsec as _, |
a7813a04 XL |
88 | }, |
89 | } | |
90 | } | |
91 | } | |
92 | ||
93 | impl PartialEq for Timespec { | |
94 | fn eq(&self, other: &Timespec) -> bool { | |
95 | self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec | |
96 | } | |
97 | } | |
98 | ||
99 | impl Eq for Timespec {} | |
100 | ||
101 | impl PartialOrd for Timespec { | |
102 | fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> { | |
103 | Some(self.cmp(other)) | |
104 | } | |
105 | } | |
106 | ||
107 | impl Ord for Timespec { | |
108 | fn cmp(&self, other: &Timespec) -> Ordering { | |
109 | let me = (self.t.tv_sec, self.t.tv_nsec); | |
110 | let other = (other.t.tv_sec, other.t.tv_nsec); | |
111 | me.cmp(&other) | |
112 | } | |
113 | } | |
114 | ||
ff7c6d11 XL |
115 | impl Hash for Timespec { |
116 | fn hash<H : Hasher>(&self, state: &mut H) { | |
117 | self.t.tv_sec.hash(state); | |
118 | self.t.tv_nsec.hash(state); | |
119 | } | |
120 | } | |
121 | ||
85aaf69f SL |
122 | #[cfg(any(target_os = "macos", target_os = "ios"))] |
123 | mod inner { | |
92a42be0 | 124 | use fmt; |
85aaf69f | 125 | use libc; |
92a42be0 SL |
126 | use sync::Once; |
127 | use sys::cvt; | |
128 | use sys_common::mul_div_u64; | |
129 | use time::Duration; | |
85aaf69f | 130 | |
a7813a04 XL |
131 | use super::NSEC_PER_SEC; |
132 | use super::Timespec; | |
92a42be0 | 133 | |
ff7c6d11 | 134 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] |
92a42be0 | 135 | pub struct Instant { |
85aaf69f SL |
136 | t: u64 |
137 | } | |
138 | ||
ff7c6d11 | 139 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
92a42be0 | 140 | pub struct SystemTime { |
a7813a04 | 141 | t: Timespec, |
85aaf69f SL |
142 | } |
143 | ||
92a42be0 | 144 | pub const UNIX_EPOCH: SystemTime = SystemTime { |
a7813a04 XL |
145 | t: Timespec { |
146 | t: libc::timespec { | |
147 | tv_sec: 0, | |
148 | tv_nsec: 0, | |
149 | }, | |
92a42be0 SL |
150 | }, |
151 | }; | |
152 | ||
153 | impl Instant { | |
154 | pub fn now() -> Instant { | |
155 | Instant { t: unsafe { libc::mach_absolute_time() } } | |
156 | } | |
157 | ||
158 | pub fn sub_instant(&self, other: &Instant) -> Duration { | |
159 | let info = info(); | |
160 | let diff = self.t.checked_sub(other.t) | |
161 | .expect("second instant is later than self"); | |
162 | let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64); | |
163 | Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32) | |
164 | } | |
165 | ||
166 | pub fn add_duration(&self, other: &Duration) -> Instant { | |
167 | Instant { | |
168 | t: self.t.checked_add(dur2intervals(other)) | |
169 | .expect("overflow when adding duration to instant"), | |
170 | } | |
171 | } | |
172 | ||
173 | pub fn sub_duration(&self, other: &Duration) -> Instant { | |
174 | Instant { | |
175 | t: self.t.checked_sub(dur2intervals(other)) | |
7cac9316 | 176 | .expect("overflow when subtracting duration from instant"), |
85aaf69f SL |
177 | } |
178 | } | |
85aaf69f SL |
179 | } |
180 | ||
92a42be0 SL |
181 | impl SystemTime { |
182 | pub fn now() -> SystemTime { | |
5bcae85e SL |
183 | use ptr; |
184 | ||
a7813a04 XL |
185 | let mut s = libc::timeval { |
186 | tv_sec: 0, | |
187 | tv_usec: 0, | |
92a42be0 SL |
188 | }; |
189 | cvt(unsafe { | |
5bcae85e | 190 | libc::gettimeofday(&mut s, ptr::null_mut()) |
92a42be0 | 191 | }).unwrap(); |
a7813a04 | 192 | return SystemTime::from(s) |
92a42be0 SL |
193 | } |
194 | ||
195 | pub fn sub_time(&self, other: &SystemTime) | |
196 | -> Result<Duration, Duration> { | |
a7813a04 | 197 | self.t.sub_timespec(&other.t) |
92a42be0 SL |
198 | } |
199 | ||
200 | pub fn add_duration(&self, other: &Duration) -> SystemTime { | |
a7813a04 | 201 | SystemTime { t: self.t.add_duration(other) } |
92a42be0 SL |
202 | } |
203 | ||
204 | pub fn sub_duration(&self, other: &Duration) -> SystemTime { | |
a7813a04 | 205 | SystemTime { t: self.t.sub_duration(other) } |
92a42be0 SL |
206 | } |
207 | } | |
208 | ||
7453a54e SL |
209 | impl From<libc::timeval> for SystemTime { |
210 | fn from(t: libc::timeval) -> SystemTime { | |
a7813a04 XL |
211 | SystemTime::from(libc::timespec { |
212 | tv_sec: t.tv_sec, | |
213 | tv_nsec: (t.tv_usec * 1000) as libc::c_long, | |
214 | }) | |
92a42be0 SL |
215 | } |
216 | } | |
217 | ||
a7813a04 XL |
218 | impl From<libc::timespec> for SystemTime { |
219 | fn from(t: libc::timespec) -> SystemTime { | |
220 | SystemTime { t: Timespec { t: t } } | |
92a42be0 SL |
221 | } |
222 | } | |
223 | ||
224 | impl fmt::Debug for SystemTime { | |
225 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
226 | f.debug_struct("SystemTime") | |
a7813a04 XL |
227 | .field("tv_sec", &self.t.t.tv_sec) |
228 | .field("tv_nsec", &self.t.t.tv_nsec) | |
92a42be0 SL |
229 | .finish() |
230 | } | |
231 | } | |
232 | ||
233 | fn dur2intervals(dur: &Duration) -> u64 { | |
234 | let info = info(); | |
235 | let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| { | |
236 | nanos.checked_add(dur.subsec_nanos() as u64) | |
237 | }).expect("overflow converting duration to nanoseconds"); | |
238 | mul_div_u64(nanos, info.denom as u64, info.numer as u64) | |
239 | } | |
240 | ||
85aaf69f SL |
241 | fn info() -> &'static libc::mach_timebase_info { |
242 | static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info { | |
243 | numer: 0, | |
244 | denom: 0, | |
245 | }; | |
62682a34 | 246 | static ONCE: Once = Once::new(); |
85aaf69f SL |
247 | |
248 | unsafe { | |
249 | ONCE.call_once(|| { | |
92a42be0 | 250 | libc::mach_timebase_info(&mut INFO); |
85aaf69f SL |
251 | }); |
252 | &INFO | |
253 | } | |
254 | } | |
85aaf69f SL |
255 | } |
256 | ||
257 | #[cfg(not(any(target_os = "macos", target_os = "ios")))] | |
258 | mod inner { | |
92a42be0 | 259 | use fmt; |
85aaf69f | 260 | use libc; |
92a42be0 SL |
261 | use sys::cvt; |
262 | use time::Duration; | |
85aaf69f | 263 | |
a7813a04 | 264 | use super::Timespec; |
85aaf69f | 265 | |
ff7c6d11 | 266 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
92a42be0 SL |
267 | pub struct Instant { |
268 | t: Timespec, | |
269 | } | |
270 | ||
ff7c6d11 | 271 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
92a42be0 SL |
272 | pub struct SystemTime { |
273 | t: Timespec, | |
274 | } | |
275 | ||
276 | pub const UNIX_EPOCH: SystemTime = SystemTime { | |
277 | t: Timespec { | |
278 | t: libc::timespec { | |
279 | tv_sec: 0, | |
280 | tv_nsec: 0, | |
281 | }, | |
282 | }, | |
283 | }; | |
85aaf69f | 284 | |
92a42be0 SL |
285 | impl Instant { |
286 | pub fn now() -> Instant { | |
a7813a04 | 287 | Instant { t: now(libc::CLOCK_MONOTONIC) } |
92a42be0 SL |
288 | } |
289 | ||
290 | pub fn sub_instant(&self, other: &Instant) -> Duration { | |
291 | self.t.sub_timespec(&other.t).unwrap_or_else(|_| { | |
94b46f34 | 292 | panic!("specified instant was later than self") |
92a42be0 SL |
293 | }) |
294 | } | |
295 | ||
296 | pub fn add_duration(&self, other: &Duration) -> Instant { | |
297 | Instant { t: self.t.add_duration(other) } | |
298 | } | |
299 | ||
300 | pub fn sub_duration(&self, other: &Duration) -> Instant { | |
301 | Instant { t: self.t.sub_duration(other) } | |
302 | } | |
303 | } | |
304 | ||
305 | impl fmt::Debug for Instant { | |
306 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
307 | f.debug_struct("Instant") | |
308 | .field("tv_sec", &self.t.t.tv_sec) | |
309 | .field("tv_nsec", &self.t.t.tv_nsec) | |
310 | .finish() | |
311 | } | |
312 | } | |
313 | ||
314 | impl SystemTime { | |
315 | pub fn now() -> SystemTime { | |
a7813a04 | 316 | SystemTime { t: now(libc::CLOCK_REALTIME) } |
92a42be0 SL |
317 | } |
318 | ||
319 | pub fn sub_time(&self, other: &SystemTime) | |
320 | -> Result<Duration, Duration> { | |
321 | self.t.sub_timespec(&other.t) | |
322 | } | |
323 | ||
324 | pub fn add_duration(&self, other: &Duration) -> SystemTime { | |
325 | SystemTime { t: self.t.add_duration(other) } | |
326 | } | |
327 | ||
328 | pub fn sub_duration(&self, other: &Duration) -> SystemTime { | |
329 | SystemTime { t: self.t.sub_duration(other) } | |
330 | } | |
331 | } | |
b039eaaf | 332 | |
7453a54e SL |
333 | impl From<libc::timespec> for SystemTime { |
334 | fn from(t: libc::timespec) -> SystemTime { | |
335 | SystemTime { t: Timespec { t: t } } | |
336 | } | |
337 | } | |
338 | ||
92a42be0 SL |
339 | impl fmt::Debug for SystemTime { |
340 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
341 | f.debug_struct("SystemTime") | |
342 | .field("tv_sec", &self.t.t.tv_sec) | |
343 | .field("tv_nsec", &self.t.t.tv_nsec) | |
344 | .finish() | |
345 | } | |
85aaf69f SL |
346 | } |
347 | ||
54a0048b SL |
348 | #[cfg(not(target_os = "dragonfly"))] |
349 | pub type clock_t = libc::c_int; | |
350 | #[cfg(target_os = "dragonfly")] | |
351 | pub type clock_t = libc::c_ulong; | |
352 | ||
a7813a04 XL |
353 | fn now(clock: clock_t) -> Timespec { |
354 | let mut t = Timespec { | |
355 | t: libc::timespec { | |
356 | tv_sec: 0, | |
357 | tv_nsec: 0, | |
92a42be0 | 358 | } |
a7813a04 XL |
359 | }; |
360 | cvt(unsafe { | |
361 | libc::clock_gettime(clock, &mut t.t) | |
362 | }).unwrap(); | |
363 | t | |
85aaf69f SL |
364 | } |
365 | } |