From cefaa3a7d53314658a0cdebd5e2e4015d1454323 Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Mon, 1 Jan 2024 21:04:07 +0000 Subject: [PATCH] Windows: Remove once_cell dependency (#21) --- CHANGELOG.md | 3 +++ Cargo.toml | 1 - src/lib.rs | 55 +++++++++++--------------------------------------- src/windows.rs | 36 +++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 44 deletions(-) create mode 100644 src/windows.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 706f552..7792cc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# Unreleased (v1.2.0) +* Windows: Remove _once_cell_ dependency. + # v1.1.1 * Fix LoopHelper increment overflow handling. diff --git a/Cargo.toml b/Cargo.toml index 5ea645e..f0bea2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/lib.rs b/src/lib.rs index ba018f9..bbd74d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,8 +48,11 @@ //! # let _ = sleeper; //! ``` mod loop_helper; +#[cfg(windows)] +mod windows; pub use crate::loop_helper::*; + use std::{ thread, time::{Duration, Instant}, @@ -80,45 +83,13 @@ 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 = - once_cell::sync::Lazy::new(|| unsafe { - use std::mem; - use winapi::um::{mmsystem::*, timeapi::timeGetDevCaps}; - - let tc_size = mem::size_of::() 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 { @@ -126,7 +97,7 @@ impl Default for SpinSleeper { #[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; @@ -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 } } diff --git a/src/windows.rs b/src/windows.rs new file mode 100644 index 0000000..be3a60e --- /dev/null +++ b/src/windows.rs @@ -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 = OnceLock::new(); + + *MIN_TIME_PERIOD.get_or_init(|| unsafe { + let tc_size = mem::size_of::() 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 + } + }) +}