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