diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2013-12-29 20:09:40 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2013-12-30 14:35:55 -0800 |
| commit | 726091fea5ab7663c6e7c7cfdde015afc0065e46 (patch) | |
| tree | 7f67c8eb6b5428e12f88e219015598b210ede0b7 /src/libextra | |
| parent | aa5d779a3590b1ed1559e0489138040a71ae688b (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.rs | 106 |
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) } } |
