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).
This commit is contained in:
Alex Crichton 2013-12-29 20:09:40 -08:00
parent aa5d779a35
commit 726091fea5
5 changed files with 202 additions and 87 deletions

View File

@ -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)
}
}

View File

@ -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")]

View File

@ -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;
}
}

View File

@ -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 {}

View File

@ -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