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