Skip to content

Hack around a getting precise time in Windows #231

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ documentation = "https://doc.rust-lang.org/time"
description = """
Utilities for working with time-related functions in Rust.
"""
build = "build.rs"

[dependencies]
libc = "0.2.1"
Expand All @@ -21,6 +22,9 @@ redox_syscall = "0.1"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.0", features = ["std", "minwinbase", "minwindef", "ntdef", "profileapi", "sysinfoapi", "timezoneapi"] }

[build-dependencies]
rustc_version = "0.2"

[dev-dependencies]
log = "0.4"
winapi = { version = "0.3.0", features = ["std", "processthreadsapi", "winbase"] }
8 changes: 8 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
extern crate rustc_version;
use rustc_version::{version, Version};

fn main() {
if version().unwrap() >= Version::parse("1.31.0").unwrap() {
println!("cargo:rustc-cfg=feature=\"has_const_fn\"");
}
}
48 changes: 46 additions & 2 deletions src/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,8 +873,52 @@ mod inner {

pub fn get_time() -> (i64, i32) {
unsafe {
let mut ft = mem::zeroed();
GetSystemTimeAsFileTime(&mut ft);
let mut ft: FILETIME = mem::zeroed();

// Based on work from: https://github.com/rust-lang/rust/issues/67266
//
// Code adapted from Rust itself:
//
// https://github.com/rust-lang/rust/blob/master/src/libstd/sys/windows/compat.rs
//
// We need one of the available functions in Windows that lets us
// get the current time. We only want to load the symbol once, because
// loading symbols is costly, and we also want to be thread-safe.

use std::sync::atomic::{AtomicUsize, Ordering};
use winapi::um::libloaderapi;

#[cfg(not(feature = "has_const_fn"))]
use std::sync::atomic::{ATOMIC_USIZE_INIT};
#[cfg(not(feature = "has_const_fn"))]
static PTR: AtomicUsize = ATOMIC_USIZE_INIT;
#[cfg(feature = "has_const_fn")]
static PTR: AtomicUsize = AtomicUsize::new(0);

let addr = match PTR.load(Ordering::SeqCst) {
0 => {
// Check if GetSystemTimePreciseAsFileTime is exported from Windows' kernel32,
// and take its address if so. Otherwise, fallback to the older
// GetSystemTimeAsFileTime function.
let module = b"kernel32\0".as_ptr() as *const i8;
let symbol = b"GetSystemTimePreciseAsFileTime\0".as_ptr() as *const i8;
let addr = {
let handle = libloaderapi::GetModuleHandleA(module);
match libloaderapi::GetProcAddress(handle, symbol) as usize {
0 => GetSystemTimeAsFileTime as usize, // fallback function
addr => addr,
}
};
PTR.store(addr, Ordering::SeqCst);
addr
}
addr => addr, // We already looked up the symbol - just return the address
};

// Call the function at `addr`:
type PFNGSTAFT = unsafe extern "system" fn(LPFILETIME);
mem::transmute::<usize, PFNGSTAFT>(addr)(&mut ft as LPFILETIME);

(file_time_to_unix_seconds(&ft), file_time_to_nsec(&ft))
}
}
Expand Down