]> git.proxmox.com Git - rustc.git/blob - src/libstd/sys/unix/time.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.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 pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
12
13 const NSEC_PER_SEC: u64 = 1_000_000_000;
14
15 #[cfg(any(target_os = "macos", target_os = "ios"))]
16 mod inner {
17 use cmp::Ordering;
18 use fmt;
19 use libc;
20 use super::NSEC_PER_SEC;
21 use sync::Once;
22 use sys::cvt;
23 use sys_common::mul_div_u64;
24 use time::Duration;
25
26 const USEC_PER_SEC: u64 = NSEC_PER_SEC / 1000;
27
28 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
29 pub struct Instant {
30 t: u64
31 }
32
33 #[derive(Copy, Clone)]
34 pub struct SystemTime {
35 t: libc::timeval,
36 }
37
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"),
69 }
70 }
71 }
72
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 - other.t.tv_sec) as u64,
92 ((self.t.tv_usec -
93 other.t.tv_usec) as u32) * 1000)
94 } else {
95 Duration::new((self.t.tv_sec - 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 From<libc::timeval> for SystemTime {
150 fn from(t: libc::timeval) -> SystemTime {
151 SystemTime { t: t }
152 }
153 }
154
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
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 };
199 static ONCE: Once = Once::new();
200
201 unsafe {
202 ONCE.call_once(|| {
203 libc::mach_timebase_info(&mut INFO);
204 });
205 &INFO
206 }
207 }
208 }
209
210 #[cfg(not(any(target_os = "macos", target_os = "ios")))]
211 mod inner {
212 use cmp::Ordering;
213 use fmt;
214 use libc;
215 use super::NSEC_PER_SEC;
216 use sys::cvt;
217 use time::Duration;
218
219 #[derive(Copy, Clone)]
220 struct Timespec {
221 t: libc::timespec,
222 }
223
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 };
242
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 }
290
291 impl From<libc::timespec> for SystemTime {
292 fn from(t: libc::timespec) -> SystemTime {
293 SystemTime { t: Timespec { t: t } }
294 }
295 }
296
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 }
304 }
305
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
311 impl Timespec {
312 pub fn now(clock: clock_t) -> Timespec {
313 let mut t = Timespec {
314 t: libc::timespec {
315 tv_sec: 0,
316 tv_nsec: 0,
317 }
318 };
319 cvt(unsafe {
320 libc::clock_gettime(clock, &mut t.t)
321 }).unwrap();
322 t
323 }
324
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 })
335 } else {
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 },
360 }
361 }
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 }
404 }
405 }