about summary refs log tree commit diff
path: root/src/libstd/sys/unix/time.rs
blob: 1104bc995c6ea7961e8b2d2a979590b75f3614d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub use self::inner::SteadyTime;

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
    use libc;
    use time::Duration;
    use ops::Sub;
    use sync::{Once, ONCE_INIT};

    pub struct SteadyTime {
        t: u64
    }

    extern {
        pub fn mach_absolute_time() -> u64;
        pub fn mach_timebase_info(info: *mut libc::mach_timebase_info) -> libc::c_int;
    }

    impl SteadyTime {
        pub fn now() -> SteadyTime {
            SteadyTime {
                t: unsafe { mach_absolute_time() },
            }
        }

        pub fn ns(&self) -> u64 {
            let info = info();
            self.t * info.numer as u64 / info.denom as u64
        }
    }

    fn info() -> &'static libc::mach_timebase_info {
        static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info {
            numer: 0,
            denom: 0,
        };
        static ONCE: Once = ONCE_INIT;

        unsafe {
            ONCE.call_once(|| {
                mach_timebase_info(&mut INFO);
            });
            &INFO
        }
    }

    impl<'a> Sub for &'a SteadyTime {
        type Output = Duration;

        fn sub(self, other: &SteadyTime) -> Duration {
            unsafe {
                let info = info();
                let diff = self.t as i64 - other.t as i64;
                Duration::nanoseconds(diff * info.numer as i64 / info.denom as i64)
            }
        }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
    use libc;
    use time::Duration;
    use ops::Sub;

    const NSEC_PER_SEC: i64 = 1_000_000_000;

    pub struct SteadyTime {
        t: libc::timespec,
    }

    // Apparently android provides this in some other library?
    // Bitrig's RT extensions are in the C library, not a separate librt
    // OpenBSD provide it via libc
    #[cfg(not(any(target_os = "android",
                  target_os = "bitrig",
                  target_os = "openbsd")))]
    #[link(name = "rt")]
    extern {}

    extern {
        fn clock_gettime(clk_id: libc::c_int, tp: *mut libc::timespec) -> libc::c_int;
    }

    impl SteadyTime {
        pub fn now() -> SteadyTime {
            let mut t = SteadyTime {
                t: libc::timespec {
                    tv_sec: 0,
                    tv_nsec: 0,
                }
            };
            unsafe {
                assert_eq!(0, clock_gettime(libc::CLOCK_MONOTONIC, &mut t.t));
            }
            t
        }

        pub fn ns(&self) -> u64 {
            self.t.tv_sec as u64 * NSEC_PER_SEC as u64 + self.t.tv_nsec as u64
        }
    }

    impl<'a> Sub for &'a SteadyTime {
        type Output = Duration;

        fn sub(self, other: &SteadyTime) -> Duration {
            if self.t.tv_nsec >= other.t.tv_nsec {
                Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) +
                    Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64)
            } else {
                Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) +
                    Duration::nanoseconds(self.t.tv_nsec as i64 + NSEC_PER_SEC -
                                          other.t.tv_nsec as i64)
            }
        }
    }
}