]>
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 { | |
54a0048b SL |
91 | Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, |
92 | ((self.t.tv_usec - | |
93 | other.t.tv_usec) as u32) * 1000) | |
92a42be0 | 94 | } else { |
54a0048b | 95 | Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, |
92a42be0 SL |
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 | ||
7453a54e SL |
149 | impl From<libc::timeval> for SystemTime { |
150 | fn from(t: libc::timeval) -> SystemTime { | |
151 | SystemTime { t: t } | |
152 | } | |
153 | } | |
154 | ||
92a42be0 SL |
155 | impl PartialEq for SystemTime { |
156 | fn eq(&self, other: &SystemTime) -> bool { | |
157 | self.t.tv_sec == other.t.tv_sec && self.t.tv_usec == other.t.tv_usec | |
158 | } | |
159 | } | |
160 | ||
161 | impl Eq for SystemTime {} | |
162 | ||
163 | impl PartialOrd for SystemTime { | |
164 | fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> { | |
165 | Some(self.cmp(other)) | |
166 | } | |
167 | } | |
168 | ||
169 | impl Ord for SystemTime { | |
170 | fn cmp(&self, other: &SystemTime) -> Ordering { | |
171 | let me = (self.t.tv_sec, self.t.tv_usec); | |
172 | let other = (other.t.tv_sec, other.t.tv_usec); | |
173 | me.cmp(&other) | |
174 | } | |
175 | } | |
176 | ||
177 | impl fmt::Debug for SystemTime { | |
178 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
179 | f.debug_struct("SystemTime") | |
180 | .field("tv_sec", &self.t.tv_sec) | |
181 | .field("tv_usec", &self.t.tv_usec) | |
182 | .finish() | |
183 | } | |
184 | } | |
185 | ||
186 | fn dur2intervals(dur: &Duration) -> u64 { | |
187 | let info = info(); | |
188 | let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| { | |
189 | nanos.checked_add(dur.subsec_nanos() as u64) | |
190 | }).expect("overflow converting duration to nanoseconds"); | |
191 | mul_div_u64(nanos, info.denom as u64, info.numer as u64) | |
192 | } | |
193 | ||
85aaf69f SL |
194 | fn info() -> &'static libc::mach_timebase_info { |
195 | static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info { | |
196 | numer: 0, | |
197 | denom: 0, | |
198 | }; | |
62682a34 | 199 | static ONCE: Once = Once::new(); |
85aaf69f SL |
200 | |
201 | unsafe { | |
202 | ONCE.call_once(|| { | |
92a42be0 | 203 | libc::mach_timebase_info(&mut INFO); |
85aaf69f SL |
204 | }); |
205 | &INFO | |
206 | } | |
207 | } | |
85aaf69f SL |
208 | } |
209 | ||
210 | #[cfg(not(any(target_os = "macos", target_os = "ios")))] | |
211 | mod inner { | |
92a42be0 SL |
212 | use cmp::Ordering; |
213 | use fmt; | |
85aaf69f | 214 | use libc; |
d9579d0f | 215 | use super::NSEC_PER_SEC; |
92a42be0 SL |
216 | use sys::cvt; |
217 | use time::Duration; | |
85aaf69f | 218 | |
92a42be0 SL |
219 | #[derive(Copy, Clone)] |
220 | struct Timespec { | |
85aaf69f SL |
221 | t: libc::timespec, |
222 | } | |
223 | ||
92a42be0 SL |
224 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] |
225 | pub struct Instant { | |
226 | t: Timespec, | |
227 | } | |
228 | ||
229 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] | |
230 | pub struct SystemTime { | |
231 | t: Timespec, | |
232 | } | |
233 | ||
234 | pub const UNIX_EPOCH: SystemTime = SystemTime { | |
235 | t: Timespec { | |
236 | t: libc::timespec { | |
237 | tv_sec: 0, | |
238 | tv_nsec: 0, | |
239 | }, | |
240 | }, | |
241 | }; | |
85aaf69f | 242 | |
92a42be0 SL |
243 | impl Instant { |
244 | pub fn now() -> Instant { | |
245 | Instant { t: Timespec::now(libc::CLOCK_MONOTONIC) } | |
246 | } | |
247 | ||
248 | pub fn sub_instant(&self, other: &Instant) -> Duration { | |
249 | self.t.sub_timespec(&other.t).unwrap_or_else(|_| { | |
250 | panic!("other was less than the current instant") | |
251 | }) | |
252 | } | |
253 | ||
254 | pub fn add_duration(&self, other: &Duration) -> Instant { | |
255 | Instant { t: self.t.add_duration(other) } | |
256 | } | |
257 | ||
258 | pub fn sub_duration(&self, other: &Duration) -> Instant { | |
259 | Instant { t: self.t.sub_duration(other) } | |
260 | } | |
261 | } | |
262 | ||
263 | impl fmt::Debug for Instant { | |
264 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
265 | f.debug_struct("Instant") | |
266 | .field("tv_sec", &self.t.t.tv_sec) | |
267 | .field("tv_nsec", &self.t.t.tv_nsec) | |
268 | .finish() | |
269 | } | |
270 | } | |
271 | ||
272 | impl SystemTime { | |
273 | pub fn now() -> SystemTime { | |
274 | SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) } | |
275 | } | |
276 | ||
277 | pub fn sub_time(&self, other: &SystemTime) | |
278 | -> Result<Duration, Duration> { | |
279 | self.t.sub_timespec(&other.t) | |
280 | } | |
281 | ||
282 | pub fn add_duration(&self, other: &Duration) -> SystemTime { | |
283 | SystemTime { t: self.t.add_duration(other) } | |
284 | } | |
285 | ||
286 | pub fn sub_duration(&self, other: &Duration) -> SystemTime { | |
287 | SystemTime { t: self.t.sub_duration(other) } | |
288 | } | |
289 | } | |
b039eaaf | 290 | |
7453a54e SL |
291 | impl From<libc::timespec> for SystemTime { |
292 | fn from(t: libc::timespec) -> SystemTime { | |
293 | SystemTime { t: Timespec { t: t } } | |
294 | } | |
295 | } | |
296 | ||
92a42be0 SL |
297 | impl fmt::Debug for SystemTime { |
298 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
299 | f.debug_struct("SystemTime") | |
300 | .field("tv_sec", &self.t.t.tv_sec) | |
301 | .field("tv_nsec", &self.t.t.tv_nsec) | |
302 | .finish() | |
303 | } | |
85aaf69f SL |
304 | } |
305 | ||
54a0048b SL |
306 | #[cfg(not(target_os = "dragonfly"))] |
307 | pub type clock_t = libc::c_int; | |
308 | #[cfg(target_os = "dragonfly")] | |
309 | pub type clock_t = libc::c_ulong; | |
310 | ||
92a42be0 | 311 | impl Timespec { |
54a0048b | 312 | pub fn now(clock: clock_t) -> Timespec { |
92a42be0 | 313 | let mut t = Timespec { |
85aaf69f SL |
314 | t: libc::timespec { |
315 | tv_sec: 0, | |
316 | tv_nsec: 0, | |
317 | } | |
318 | }; | |
92a42be0 SL |
319 | cvt(unsafe { |
320 | libc::clock_gettime(clock, &mut t.t) | |
321 | }).unwrap(); | |
85aaf69f SL |
322 | t |
323 | } | |
85aaf69f | 324 | |
92a42be0 SL |
325 | fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { |
326 | if self >= other { | |
327 | Ok(if self.t.tv_nsec >= other.t.tv_nsec { | |
328 | Duration::new((self.t.tv_sec - other.t.tv_sec) as u64, | |
329 | (self.t.tv_nsec - other.t.tv_nsec) as u32) | |
330 | } else { | |
331 | Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64, | |
332 | self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - | |
333 | other.t.tv_nsec as u32) | |
334 | }) | |
85aaf69f | 335 | } else { |
92a42be0 SL |
336 | match other.sub_timespec(self) { |
337 | Ok(d) => Err(d), | |
338 | Err(d) => Ok(d), | |
339 | } | |
340 | } | |
341 | } | |
342 | ||
343 | fn add_duration(&self, other: &Duration) -> Timespec { | |
344 | let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64); | |
345 | let mut secs = secs.expect("overflow when adding duration to time"); | |
346 | ||
347 | // Nano calculations can't overflow because nanos are <1B which fit | |
348 | // in a u32. | |
349 | let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; | |
350 | if nsec >= NSEC_PER_SEC as u32 { | |
351 | nsec -= NSEC_PER_SEC as u32; | |
352 | secs = secs.checked_add(1).expect("overflow when adding \ | |
353 | duration to time"); | |
354 | } | |
355 | Timespec { | |
356 | t: libc::timespec { | |
357 | tv_sec: secs as libc::time_t, | |
358 | tv_nsec: nsec as libc::c_long, | |
359 | }, | |
85aaf69f SL |
360 | } |
361 | } | |
92a42be0 SL |
362 | |
363 | fn sub_duration(&self, other: &Duration) -> Timespec { | |
364 | let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64); | |
365 | let mut secs = secs.expect("overflow when subtracting duration \ | |
366 | from time"); | |
367 | ||
368 | // Similar to above, nanos can't overflow. | |
369 | let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; | |
370 | if nsec < 0 { | |
371 | nsec += NSEC_PER_SEC as i32; | |
372 | secs = secs.checked_sub(1).expect("overflow when subtracting \ | |
373 | duration from time"); | |
374 | } | |
375 | Timespec { | |
376 | t: libc::timespec { | |
377 | tv_sec: secs as libc::time_t, | |
378 | tv_nsec: nsec as libc::c_long, | |
379 | }, | |
380 | } | |
381 | } | |
382 | } | |
383 | ||
384 | impl PartialEq for Timespec { | |
385 | fn eq(&self, other: &Timespec) -> bool { | |
386 | self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec | |
387 | } | |
388 | } | |
389 | ||
390 | impl Eq for Timespec {} | |
391 | ||
392 | impl PartialOrd for Timespec { | |
393 | fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> { | |
394 | Some(self.cmp(other)) | |
395 | } | |
396 | } | |
397 | ||
398 | impl Ord for Timespec { | |
399 | fn cmp(&self, other: &Timespec) -> Ordering { | |
400 | let me = (self.t.tv_sec, self.t.tv_nsec); | |
401 | let other = (other.t.tv_sec, other.t.tv_nsec); | |
402 | me.cmp(&other) | |
403 | } | |
85aaf69f SL |
404 | } |
405 | } |