about summary refs log tree commit diff
path: root/src/libstd/sys/unix/time.rs
blob: db0d0f150613953e5100878c7930ae1468656e73 (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
// 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;

const NSEC_PER_SEC: u64 = 1_000_000_000;

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

    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() },
            }
        }
    }

    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::new();

        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 {
            let info = info();
            let diff = self.t as u64 - other.t as u64;
            let nanos = diff * info.numer as u64 / info.denom as u64;
            Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)
        }
    }
}

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

    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 = "netbsd",
                  target_os = "openbsd",
                  target_env = "musl")))]
    #[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
        }
    }

    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::new(self.t.tv_sec as u64 - other.t.tv_sec as u64,
                              self.t.tv_nsec as u32 - other.t.tv_nsec as u32)
            } else {
                Duration::new(self.t.tv_sec as u64 - 1 - other.t.tv_sec as u64,
                              self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
                                          other.t.tv_nsec as u32)
            }
        }
    }
}