about summary refs log tree commit diff
path: root/src/libextra
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-12-29 20:09:40 -0800
committerAlex Crichton <alex@alexcrichton.com>2013-12-30 14:35:55 -0800
commit726091fea5ab7663c6e7c7cfdde015afc0065e46 (patch)
tree7f67c8eb6b5428e12f88e219015598b210ede0b7 /src/libextra
parentaa5d779a3590b1ed1559e0489138040a71ae688b (diff)
Convert some C functions to rust functions
Right now on linux, an empty executable with LTO still depends on librt becaues
of the clock_gettime function in rust_builtin.o, but this commit moves this
dependency into a rust function which is subject to elimination via LTO.

At the same time, this also drops libstd's dependency on librt on unices that
are not OSX because the library is only used by extra::time (and now the
dependency is listed in that module instead).
Diffstat (limited to 'src/libextra')
-rw-r--r--src/libextra/time.rs106
1 files changed, 96 insertions, 10 deletions
diff --git a/src/libextra/time.rs b/src/libextra/time.rs
index 6204f9f4ce0..23c81c6fce5 100644
--- a/src/libextra/time.rs
+++ b/src/libextra/time.rs
@@ -12,17 +12,16 @@
 
 use std::io::Reader;
 use std::io::mem::BufReader;
+use std::libc;
 use std::num;
 use std::str;
 
 static NSEC_PER_SEC: i32 = 1_000_000_000_i32;
 
-pub mod rustrt {
+mod rustrt {
     use super::Tm;
 
     extern {
-        pub fn rust_get_time(sec: &mut i64, nsec: &mut i32);
-        pub fn rust_precise_time_ns(ns: &mut u64);
         pub fn rust_tzset();
         pub fn rust_gmtime(sec: i64, nsec: i32, result: &mut Tm);
         pub fn rust_localtime(sec: i64, nsec: i32, result: &mut Tm);
@@ -31,6 +30,31 @@ pub mod rustrt {
     }
 }
 
+#[cfg(unix, not(target_os = "macos"))]
+mod imp {
+    use std::libc::{c_int, timespec};
+
+    // Apparently android provides this in some other library?
+    #[cfg(not(target_os = "android"))]
+    #[link(name = "rt")]
+    extern {}
+
+    extern {
+        pub fn clock_gettime(clk_id: c_int, tp: *mut timespec) -> c_int;
+    }
+
+}
+#[cfg(target_os = "macos")]
+mod imp {
+    use std::libc::{timeval, timezone, c_int, mach_timebase_info};
+
+    extern {
+        pub fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int;
+        pub fn mach_absolute_time() -> u64;
+        pub fn mach_timebase_info(info: *mut mach_timebase_info) -> c_int;
+    }
+}
+
 /// A record specifying a time value in seconds and nanoseconds.
 
 
@@ -64,11 +88,45 @@ impl Ord for Timespec {
  */
 pub fn get_time() -> Timespec {
     unsafe {
-        let mut sec = 0i64;
-        let mut nsec = 0i32;
-        rustrt::rust_get_time(&mut sec, &mut nsec);
+        let (sec, nsec) = os_get_time();
         return Timespec::new(sec, nsec);
     }
+
+    #[cfg(windows)]
+    unsafe fn os_get_time() -> (i64, i32) {
+        static NANOSECONDS_FROM_1601_TO_1970: u64 = 11644473600000000;
+
+        let mut time = libc::FILETIME {
+            dwLowDateTime: 0,
+            dwHighDateTime: 0,
+        };
+        libc::GetSystemTimeAsFileTime(&mut time);
+
+        // A FILETIME contains a 64-bit value representing the number of
+        // hectonanosecond (100-nanosecond) intervals since 1601-01-01T00:00:00Z.
+        // http://support.microsoft.com/kb/167296/en-us
+        let ns_since_1601 = ((time.dwHighDateTime as u64 << 32) |
+                             (time.dwLowDateTime  as u64 <<  0)) / 10;
+        let ns_since_1970 = ns_since_1601 - NANOSECONDS_FROM_1601_TO_1970;
+
+        ((ns_since_1970 / 1000000) as i64,
+         ((ns_since_1970 % 1000000) * 1000) as i32)
+    }
+
+    #[cfg(target_os = "macos")]
+    unsafe fn os_get_time() -> (i64, i32) {
+        use std::ptr;
+        let mut tv = libc::timeval { tv_sec: 0, tv_usec: 0 };
+        imp::gettimeofday(&mut tv, ptr::mut_null());
+        (tv.tv_sec as i64, tv.tv_usec * 1000)
+    }
+
+    #[cfg(not(target_os = "macos"), not(windows))]
+    unsafe fn os_get_time() -> (i64, i32) {
+        let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
+        imp::clock_gettime(libc::CLOCK_REALTIME, &mut tv);
+        (tv.tv_sec as i64, tv.tv_nsec as i32)
+    }
 }
 
 
@@ -77,10 +135,38 @@ pub fn get_time() -> Timespec {
  * in nanoseconds since an unspecified epoch.
  */
 pub fn precise_time_ns() -> u64 {
-    unsafe {
-        let mut ns = 0u64;
-        rustrt::rust_precise_time_ns(&mut ns);
-        ns
+    return os_precise_time_ns();
+
+    #[cfg(windows)]
+    fn os_precise_time_ns() -> u64 {
+        let mut ticks_per_s = 0;
+        assert_eq!(unsafe {
+            libc::QueryPerformanceFrequency(&mut ticks_per_s)
+        }, 1);
+        let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s};
+        let mut ticks = 0;
+        assert_eq!(unsafe {
+            libc::QueryPerformanceCounter(&mut ticks)
+        }, 1);
+
+        return (ticks as u64 * 1000000000) / (ticks_per_s as u64);
+    }
+
+    #[cfg(target_os = "macos")]
+    fn os_precise_time_ns() -> u64 {
+        let time = unsafe { imp::mach_absolute_time() };
+        let mut info = libc::mach_timebase_info { numer: 0, denom: 0 };
+        unsafe { imp::mach_timebase_info(&mut info); }
+        return time * ((info.numer / info.denom) as u64);
+    }
+
+    #[cfg(not(windows), not(target_os = "macos"))]
+    fn os_precise_time_ns() -> u64 {
+        let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
+        unsafe {
+            imp::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts);
+        }
+        return (ts.tv_sec as u64) * 1000000000 + (ts.tv_nsec as u64)
     }
 }