Skip to content

Commit

Permalink
Windows: Remove once_cell dependency (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexheretic authored Jan 1, 2024
1 parent b7f4399 commit cefaa3a
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 44 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Unreleased (v1.2.0)
* Windows: Remove _once_cell_ dependency.

# v1.1.1
* Fix LoopHelper increment overflow handling.

Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ readme="README.md"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["minwindef", "mmsystem", "timeapi"] }
once_cell = "1"

[dev-dependencies]
approx = "0.5"
Expand Down
55 changes: 12 additions & 43 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@
//! # let _ = sleeper;
//! ```
mod loop_helper;
#[cfg(windows)]
mod windows;

pub use crate::loop_helper::*;

use std::{
thread,
time::{Duration, Instant},
Expand Down Expand Up @@ -80,53 +83,21 @@ const DEFAULT_NATIVE_SLEEP_ACCURACY: SubsecondNanoseconds = 125_000;
/// Equivalent to [`std::thread::sleep`], with the following exceptions:
/// * **Windows**: Automatically selects the best native sleep accuracy generally achieving ~1ms
/// native sleep accuracy, instead of default ~16ms.
#[cfg(not(windows))]
#[inline]
pub fn native_sleep(duration: Duration) {
thread::sleep(duration)
}

#[cfg(windows)]
static MIN_TIME_PERIOD: once_cell::sync::Lazy<winapi::shared::minwindef::UINT> =
once_cell::sync::Lazy::new(|| unsafe {
use std::mem;
use winapi::um::{mmsystem::*, timeapi::timeGetDevCaps};

let tc_size = mem::size_of::<TIMECAPS>() as u32;
let mut tc = TIMECAPS {
wPeriodMin: 0,
wPeriodMax: 0,
};

if timeGetDevCaps(&mut tc as *mut TIMECAPS, tc_size) == TIMERR_NOERROR {
tc.wPeriodMin
} else {
1
}
});
#[cfg(windows)]
windows::native_sleep(duration);

/// Asks the OS to put the current thread to sleep for at least the specified amount of time.
///
/// Equivalent to [`std::thread::sleep`], with the following exceptions:
/// * **Windows**: Automatically selects the best native sleep accuracy generally achieving ~1ms
/// native sleep accuracy, instead of default ~16ms.
#[cfg(windows)]
#[inline]
pub fn native_sleep(duration: Duration) {
unsafe {
use winapi::um::timeapi::{timeBeginPeriod, timeEndPeriod};
timeBeginPeriod(*MIN_TIME_PERIOD);
thread::sleep(duration);
timeEndPeriod(*MIN_TIME_PERIOD);
}
#[cfg(not(windows))]
thread::sleep(duration);
}

impl Default for SpinSleeper {
/// Constructs new SpinSleeper with defaults suiting the current OS
#[inline]
fn default() -> Self {
#[cfg(windows)]
let accuracy = *MIN_TIME_PERIOD * 1_000_000;
let accuracy = windows::min_time_period() * 1_000_000;
#[cfg(not(windows))]
let accuracy = DEFAULT_NATIVE_SLEEP_ACCURACY;

Expand Down Expand Up @@ -227,13 +198,11 @@ pub enum SpinStrategy {
/// * !Windows `YieldThread`
impl Default for SpinStrategy {
#[inline]
#[cfg(windows)]
fn default() -> Self {
Self::SpinLoopHint
}
#[inline]
#[cfg(not(windows))]
fn default() -> Self {
#[cfg(windows)]
return Self::SpinLoopHint;

#[cfg(not(windows))]
Self::YieldThread
}
}
Expand Down
36 changes: 36 additions & 0 deletions src/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::{mem, sync::OnceLock, time::Duration};
use winapi::{
shared::minwindef::UINT,
um::{
mmsystem::{TIMECAPS, TIMERR_NOERROR},
timeapi::{timeBeginPeriod, timeEndPeriod, timeGetDevCaps},
},
};

#[inline]
pub fn native_sleep(duration: Duration) {
let min_time_period = min_time_period();
unsafe {
timeBeginPeriod(min_time_period);
std::thread::sleep(duration);
timeEndPeriod(min_time_period);
}
}

pub(crate) fn min_time_period() -> UINT {
static MIN_TIME_PERIOD: OnceLock<UINT> = OnceLock::new();

*MIN_TIME_PERIOD.get_or_init(|| unsafe {
let tc_size = mem::size_of::<TIMECAPS>() as u32;
let mut tc = TIMECAPS {
wPeriodMin: 0,
wPeriodMax: 0,
};

if timeGetDevCaps(&mut tc as *mut TIMECAPS, tc_size) == TIMERR_NOERROR {
tc.wPeriodMin
} else {
1
}
})
}

0 comments on commit cefaa3a

Please sign in to comment.