Skip to content

Commit

Permalink
add windows support to clocksource
Browse files Browse the repository at this point in the history
Adds windows support to clocksource
  • Loading branch information
brayniac committed Dec 15, 2023
1 parent f71961d commit df17ecd
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 83 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cargo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-12 ]
os: [ ubuntu-latest, macos-latest, windows-latest ]
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
Expand Down
3 changes: 3 additions & 0 deletions clocksource/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ repository = "https://github.com/pelikan-io/rustcommon"
[dependencies]
libc = "0.2.147"
time = { version = "0.3.27", features = ["formatting"] }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.9", features = ["ntdef", "profileapi", "sysinfoapi"] }
29 changes: 1 addition & 28 deletions clocksource/src/coarse/instant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,8 @@ pub struct Instant {

impl Instant {
/// Return an `Instant` that represents the current moment.
#[cfg(not(target_os = "macos"))]
pub fn now() -> Self {
let mut ts = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
unsafe {
libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, &mut ts);
}

let now = ts.tv_sec as u32;

Self { secs: now }
}

/// Return an `Instant` that represents the current moment.
#[cfg(target_os = "macos")]
pub fn now() -> Self {
let mut ts = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
unsafe {
libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts);
}

let now = ts.tv_sec as u32;

Self { secs: now }
crate::sys::monotonic::coarse()
}

/// Return the elapsed time, in nanoseconds, since the original timestamp.
Expand Down
29 changes: 1 addition & 28 deletions clocksource/src/coarse/unix_instant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,35 +31,8 @@ impl UnixInstant {
pub const EPOCH: UnixInstant = UnixInstant { secs: 0 };

/// Return a `UnixInstant` that represents the current moment.
#[cfg(not(target_os = "macos"))]
pub fn now() -> Self {
let mut ts = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
unsafe {
libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, &mut ts);
}

let now = ts.tv_sec as u32;

Self { secs: now }
}

/// Return a `UnixInstant` that represents the current moment.
#[cfg(target_os = "macos")]
pub fn now() -> Self {
let mut ts = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
unsafe {
libc::clock_gettime(libc::CLOCK_REALTIME, &mut ts);
}

let now = ts.tv_sec as u32;

Self { secs: now }
crate::sys::realtime::coarse()
}

/// Return the elapsed time, in nanoseconds, since the original timestamp.
Expand Down
2 changes: 2 additions & 0 deletions clocksource/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@
pub mod coarse;
pub mod datetime;
pub mod precise;

mod sys;
14 changes: 1 addition & 13 deletions clocksource/src/precise/instant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,7 @@ pub struct Instant {
impl Instant {
/// Return an `Instant` that represents the current moment.
pub fn now() -> Self {
let mut ts = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
unsafe {
libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts);
}

let now = (ts.tv_sec as u64)
.wrapping_mul(1_000_000_000)
.wrapping_add(ts.tv_nsec as u64);

Self { ns: now }
crate::sys::monotonic::precise()
}

/// Return the elapsed time, in nanoseconds, since the original timestamp.
Expand Down
14 changes: 1 addition & 13 deletions clocksource/src/precise/unix_instant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,7 @@ impl UnixInstant {

/// Return a `UnixInstant` that represents the current moment in time.
pub fn now() -> Self {
let mut ts = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};
unsafe {
libc::clock_gettime(libc::CLOCK_REALTIME, &mut ts);
}

let now = (ts.tv_sec as u64)
.wrapping_mul(1_000_000_000)
.wrapping_add(ts.tv_nsec as u64);

Self { ns: now }
crate::sys::realtime::precise()
}

/// Return the elapsed time, in nanoseconds, since the original timestamp.
Expand Down
9 changes: 9 additions & 0 deletions clocksource/src/sys/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#[cfg(not(target_os = "windows"))]
mod unix;
#[cfg(not(target_os = "windows"))]
pub use unix::*;

#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
pub use windows::*;
68 changes: 68 additions & 0 deletions clocksource/src/sys/unix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#[cfg(any(target_os = "macos", target_os = "ios"))]
const CLOCK_MONOTONIC_COARSE: u32 = libc::CLOCK_MONOTONIC;

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
const CLOCK_MONOTONIC_COARSE: u32 = libc::CLOCK_MONOTONIC_COARSE;

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

#[cfg(any(target_os = "macos", target_os = "ios"))]
const CLOCK_REALTIME_COARSE: u32 = libc::CLOCK_REALTIME;

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
const CLOCK_REALTIME_COARSE: u32 = libc::CLOCK_REALTIME_COARSE;

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

pub fn read_clock(clock: u32) -> libc::timespec {
let mut ts = libc::timespec {
tv_sec: 0,
tv_nsec: 0,
};

unsafe {
libc::clock_gettime(clock, &mut ts);

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types
}

ts
}

pub mod monotonic {
use super::*;

pub fn coarse() -> crate::coarse::Instant {
let ts = read_clock(CLOCK_MONOTONIC_COARSE);

let now = ts.tv_sec as u32;

crate::coarse::Instant { secs: now }
}

pub fn precise() -> crate::precise::Instant {
let ts = read_clock(libc::CLOCK_MONOTONIC);

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

let now = (ts.tv_sec as u64)
.wrapping_mul(1_000_000_000)
.wrapping_add(ts.tv_nsec as u64);

crate::precise::Instant { ns: now }
}
}

pub mod realtime {
use super::*;

pub fn coarse() -> crate::coarse::UnixInstant {
let ts = read_clock(CLOCK_REALTIME_COARSE);

let now = ts.tv_sec as u32;

crate::coarse::UnixInstant { secs: now }
}

pub fn precise() -> crate::precise::UnixInstant {
let ts = read_clock(libc::CLOCK_REALTIME);

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

Check failure

Code scanning / clippy

mismatched types Error

mismatched types

let now = (ts.tv_sec as u64)
.wrapping_mul(1_000_000_000)
.wrapping_add(ts.tv_nsec as u64);

crate::precise::UnixInstant { ns: now }
}
}
95 changes: 95 additions & 0 deletions clocksource/src/sys/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use core::sync::atomic::{AtomicU64, Ordering};

const NANOS_PER_SEC: u64 = 1_000_000_000;

pub mod monotonic {
use super::*;

use winapi::um::winnt::LARGE_INTEGER;

static FREQUENCY: AtomicU64 = AtomicU64::new(0);

fn frequency() -> u64 {
let cached = FREQUENCY.load(Ordering::Relaxed);

if cached != 0 {
return cached;
}

let frequency;
unsafe {
let mut frq: LARGE_INTEGER = core::mem::zeroed();
let _ = winapi::um::profileapi::QueryPerformanceFrequency(&mut frq);
frequency = *frq.QuadPart() as u64;
}

FREQUENCY.store(frequency, Ordering::Relaxed);
frequency
}

fn count() -> u64 {
unsafe {
let mut cnt: LARGE_INTEGER = core::mem::zeroed();
let _ = winapi::um::profileapi::QueryPerformanceCounter(&mut cnt);
*cnt.QuadPart() as u64
}
}

pub fn coarse() -> crate::coarse::Instant {
let count = count();
let frequency = frequency();

let q = count / frequency;
let r = count % frequency;

crate::coarse::Instant {
secs: (q + r / frequency) as u32
}
}

pub fn precise() -> crate::precise::Instant {
let count = count();
let frequency = frequency();

let q = count / frequency;
let r = count % frequency;

crate::precise::Instant {
ns: q * NANOS_PER_SEC + r * NANOS_PER_SEC / frequency
}
}
}

pub mod realtime {
use super::*;

use winapi::shared::minwindef::FILETIME;

const UNIX_EPOCH_INTERVALS: u64 = 116_444_736 * NANOS_PER_SEC;
const NANOS_PER_INTERVAL: u64 = 100;

const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / NANOS_PER_INTERVAL;

fn unix_intervals() -> u64 {
let filetime;
unsafe {
let mut ft: FILETIME = core::mem::zeroed();
let _ = winapi::um::sysinfoapi::GetSystemTimePreciseAsFileTime(&mut ft);
filetime = (core::mem::transmute::<FILETIME, i64>(ft)) as u64;
}

filetime - UNIX_EPOCH_INTERVALS
}

pub fn coarse() -> crate::coarse::UnixInstant {
crate::coarse::UnixInstant {
secs: (unix_intervals() / INTERVALS_PER_SEC) as u32
}
}

pub fn precise() -> crate::precise::UnixInstant {
crate::precise::UnixInstant {
ns: unix_intervals() * NANOS_PER_INTERVAL
}
}
}

0 comments on commit df17ecd

Please sign in to comment.