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) } } diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index dfe67f050ec..eefccf05a54 100644 --- a/src/librustuv/uvll.rs +++ b/src/librustuv/uvll.rs @@ -739,6 +739,10 @@ extern { #[link(name = "pthread")] extern {} +#[cfg(target_os = "linux")] +#[link(name = "rt")] +extern {} + #[cfg(target_os = "win32")] #[link(name = "ws2_32")] #[link(name = "psapi")] diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 2696e27c373..fdfc28d9d10 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -226,7 +226,8 @@ pub mod types { pub mod common { pub mod posix01 { use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, c_ulong, size_t}; + use libc::types::os::arch::c95::{c_char, c_ulong, size_t, + time_t, suseconds_t, c_long}; pub type pthread_t = c_ulong; @@ -241,6 +242,18 @@ pub mod types { __unused4: *c_void, __unused5: *c_void, } + + pub struct timeval { + tv_sec: time_t, + tv_usec: suseconds_t, + } + + pub struct timespec { + tv_sec: time_t, + tv_nsec: c_long, + } + + pub enum timezone {} } pub mod bsd44 { pub type socklen_t = u32; @@ -298,6 +311,7 @@ pub mod types { pub type ptrdiff_t = i32; pub type clock_t = i32; pub type time_t = i32; + pub type suseconds_t = i32; pub type wchar_t = i32; } pub mod c99 { @@ -481,6 +495,7 @@ pub mod types { pub type ptrdiff_t = i64; pub type clock_t = i64; pub type time_t = i64; + pub type suseconds_t = i64; pub type wchar_t = i32; } pub mod c99 { @@ -553,7 +568,8 @@ pub mod types { pub mod common { pub mod posix01 { use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, c_int, size_t}; + use libc::types::os::arch::c95::{c_char, c_int, size_t, + time_t, suseconds_t, c_long}; use libc::types::os::arch::c99::{uintptr_t}; pub type pthread_t = uintptr_t; @@ -573,6 +589,18 @@ pub mod types { __unused7: *c_void, __unused8: *c_void, } + + pub struct timeval { + tv_sec: time_t, + tv_usec: suseconds_t, + } + + pub struct timespec { + tv_sec: time_t, + tv_nsec: c_long, + } + + pub enum timezone {} } pub mod bsd44 { pub type socklen_t = u32; @@ -633,6 +661,7 @@ pub mod types { pub type ptrdiff_t = i64; pub type clock_t = i32; pub type time_t = i64; + pub type suseconds_t = i64; pub type wchar_t = i32; } pub mod c99 { @@ -709,7 +738,8 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { - use libc::types::os::arch::c95::c_short; + use libc::types::os::arch::c95::{c_short, time_t, suseconds_t, + c_long}; use libc::types::os::arch::extra::{int64, time64_t}; use libc::types::os::arch::posix88::{dev_t, ino_t}; use libc::types::os::arch::posix88::mode_t; @@ -735,6 +765,18 @@ pub mod types { actime: time64_t, modtime: time64_t, } + + pub struct timeval { + tv_sec: time_t, + tv_usec: suseconds_t, + } + + pub struct timespec { + tv_sec: time_t, + tv_nsec: c_long, + } + + pub enum timezone {} } pub mod bsd44 { @@ -807,6 +849,11 @@ pub mod types { #[cfg(target_arch = "x86_64")] pub type time_t = i64; + #[cfg(target_arch = "x86")] + pub type suseconds_t = i32; + #[cfg(target_arch = "x86_64")] + pub type suseconds_t = i64; + pub type wchar_t = u16; } @@ -983,6 +1030,13 @@ pub mod types { } pub type LPOVERLAPPED = *mut OVERLAPPED; + + pub struct FILETIME { + dwLowDateTime: DWORD, + dwHighDateTime: DWORD, + } + + pub type LPFILETIME = *mut FILETIME; } } } @@ -991,8 +1045,9 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { - use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, c_int, size_t}; + use libc::types::common::c95::c_void; + use libc::types::os::arch::c95::{c_char, c_int, size_t, + time_t, suseconds_t, c_long}; use libc::types::os::arch::c99::{uintptr_t}; pub type pthread_t = uintptr_t; @@ -1012,6 +1067,18 @@ pub mod types { __unused7: *c_void, __unused8: *c_void, } + + pub struct timeval { + tv_sec: time_t, + tv_usec: suseconds_t, + } + + pub struct timespec { + tv_sec: time_t, + tv_nsec: c_long, + } + + pub enum timezone {} } pub mod bsd44 { @@ -1075,6 +1142,7 @@ pub mod types { pub type ptrdiff_t = i32; pub type clock_t = u32; pub type time_t = i32; + pub type suseconds_t = i32; pub type wchar_t = i32; } pub mod c99 { @@ -1144,6 +1212,12 @@ pub mod types { pub mod bsd44 { } pub mod extra { + pub struct mach_timebase_info { + numer: u32, + denom: u32, + } + + pub type mach_timebase_info_data_t = mach_timebase_info; } } @@ -1165,6 +1239,7 @@ pub mod types { pub type ptrdiff_t = i64; pub type clock_t = u64; pub type time_t = i64; + pub type suseconds_t = i32; pub type wchar_t = i32; } pub mod c99 { @@ -1235,6 +1310,12 @@ pub mod types { pub mod bsd44 { } pub mod extra { + pub struct mach_timebase_info { + numer: u32, + denom: u32, + } + + pub type mach_timebase_info_data_t = mach_timebase_info; } } } @@ -2047,6 +2128,9 @@ pub mod consts { pub static PTHREAD_CREATE_JOINABLE: c_int = 0; pub static PTHREAD_CREATE_DETACHED: c_int = 1; + + pub static CLOCK_REALTIME: c_int = 0; + pub static CLOCK_MONOTONIC: c_int = 1; } pub mod posix08 { } @@ -2467,6 +2551,9 @@ pub mod consts { pub static PTHREAD_CREATE_JOINABLE: c_int = 0; pub static PTHREAD_CREATE_DETACHED: c_int = 1; + + pub static CLOCK_REALTIME: c_int = 0; + pub static CLOCK_MONOTONIC: c_int = 4; } pub mod posix08 { } @@ -3609,8 +3696,7 @@ pub mod funcs { #[cfg(target_os = "freebsd")] pub mod bsd44 { use libc::types::common::c95::{c_void}; - use libc::types::os::arch::c95::{c_char, c_uchar, c_int, c_uint, - size_t}; + use libc::types::os::arch::c95::{c_char, c_uchar, c_int, c_uint, size_t}; extern { pub fn sysctl(name: *c_int, @@ -3694,7 +3780,7 @@ pub mod funcs { LPMEMORY_BASIC_INFORMATION, LPSYSTEM_INFO}; use libc::types::os::arch::extra::{HANDLE, LPHANDLE, LARGE_INTEGER, - PLARGE_INTEGER}; + PLARGE_INTEGER, LPFILETIME}; extern "system" { pub fn GetEnvironmentVariableW(n: LPCWSTR, @@ -3838,6 +3924,14 @@ pub mod funcs { lpNewFilePointer: PLARGE_INTEGER, dwMoveMethod: DWORD) -> BOOL; pub fn SetEndOfFile(hFile: HANDLE) -> BOOL; + + pub fn GetSystemTimeAsFileTime( + lpSystemTimeAsFileTime: LPFILETIME); + + pub fn QueryPerformanceFrequency( + lpFrequency: *mut LARGE_INTEGER) -> BOOL; + pub fn QueryPerformanceCounter( + lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL; } } diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index 1ecfc1f25d0..045cdf574f6 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -22,7 +22,6 @@ extern {} // On linux librt and libdl are indirect dependencies via rustrt, // and binutils 2.22+ won't add them automatically #[cfg(target_os = "linux")] -#[link(name = "rt")] #[link(name = "dl")] #[link(name = "m")] #[link(name = "pthread")] @@ -36,7 +35,6 @@ extern {} #[cfg(target_os = "freebsd")] #[link(name = "execinfo")] -#[link(name = "rt")] #[link(name = "pthread")] extern {} diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c index f14554fd65b..6de5f808290 100644 --- a/src/rt/rust_builtin.c +++ b/src/rt/rust_builtin.c @@ -127,73 +127,6 @@ rust_list_dir_wfd_fp_buf(void* wfd) { } #endif -#if defined(__WIN32__) -void -rust_get_time(int64_t *sec, int32_t *nsec) { - FILETIME fileTime; - GetSystemTimeAsFileTime(&fileTime); - - // 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 - ULARGE_INTEGER ul; - ul.LowPart = fileTime.dwLowDateTime; - ul.HighPart = fileTime.dwHighDateTime; - uint64_t ns_since_1601 = ul.QuadPart / 10; - - const uint64_t NANOSECONDS_FROM_1601_TO_1970 = 11644473600000000ull; - uint64_t ns_since_1970 = ns_since_1601 - NANOSECONDS_FROM_1601_TO_1970; - *sec = ns_since_1970 / 1000000; - *nsec = (ns_since_1970 % 1000000) * 1000; -} -#else -void -rust_get_time(int64_t *sec, int32_t *nsec) { -#ifdef __APPLE__ - struct timeval tv; - gettimeofday(&tv, NULL); - *sec = tv.tv_sec; - *nsec = tv.tv_usec * 1000; -#else - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - *sec = ts.tv_sec; - *nsec = ts.tv_nsec; -#endif -} -#endif - -const int64_t ns_per_s = 1000000000LL; - -void -rust_precise_time_ns(uint64_t *ns) { - -#ifdef __APPLE__ - uint64_t time = mach_absolute_time(); - mach_timebase_info_data_t info = {0, 0}; - if (info.denom == 0) { - mach_timebase_info(&info); - } - uint64_t time_nano = time * (info.numer / info.denom); - *ns = time_nano; -#elif __WIN32__ - LARGE_INTEGER ticks_per_s; - BOOL query_result = QueryPerformanceFrequency(&ticks_per_s); - assert(query_result); - if (ticks_per_s.QuadPart == 0LL) { - ticks_per_s.QuadPart = 1LL; - } - LARGE_INTEGER ticks; - query_result = QueryPerformanceCounter(&ticks); - assert(query_result); - *ns = (uint64_t)((ticks.QuadPart * ns_per_s) / ticks_per_s.QuadPart); -#else - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - *ns = (uint64_t)(ts.tv_sec * ns_per_s + ts.tv_nsec); -#endif -} - typedef struct { size_t fill; // in bytes; if zero, heapified