Skip to main content

std\sys\pal\windows/
time.rs

1use crate::ops::Neg;
2use crate::ptr::null;
3use crate::sys::pal::c;
4use crate::time::Duration;
5
6const NANOS_PER_SEC: u64 = 1_000_000_000;
7pub const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
8
9pub fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
10    dur.as_secs()
11        .checked_mul(INTERVALS_PER_SEC)?
12        .checked_add(dur.subsec_nanos() as u64 / 100)?
13        .try_into()
14        .ok()
15}
16
17pub fn intervals2dur(intervals: u64) -> Duration {
18    Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32)
19}
20
21pub mod perf_counter {
22    use super::NANOS_PER_SEC;
23    use crate::sync::atomic::{AtomicI64, Ordering};
24    use crate::sys::{c, cvt};
25    use crate::time::Duration;
26
27    pub fn now() -> i64 {
28        let mut qpc_value: i64 = 0;
29        cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap();
30        qpc_value
31    }
32
33    pub fn frequency() -> i64 {
34        // Either the cached result of `QueryPerformanceFrequency` or `0` for
35        // uninitialized. Storing this as a single `AtomicI64` allows us to use
36        // `Relaxed` operations, as we are only interested in the effects on a
37        // single memory location.
38        static FREQUENCY: AtomicI64 = AtomicI64::new(0);
39
40        let cached = FREQUENCY.load(Ordering::Relaxed);
41        // If a previous thread has filled in this global state, use that.
42        if cached != 0 {
43            return cached;
44        }
45        // ... otherwise learn for ourselves ...
46        frequency_init(&FREQUENCY)
47    }
48
49    #[cold]
50    fn frequency_init(cache: &AtomicI64) -> i64 {
51        let mut frequency = 0;
52        unsafe {
53            cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap();
54        }
55
56        // SAFETY: According to the MSDN entry for `QueryPerformanceFrequency`,
57        // a value of 0 will never be returned starting from Windows XP.
58        unsafe { crate::hint::assert_unchecked(frequency != 0) }
59
60        cache.store(frequency, Ordering::Relaxed);
61        frequency
62    }
63
64    // Per microsoft docs, the margin of error for cross-thread time comparisons
65    // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
66    // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
67    //                   /acquiring-high-resolution-time-stamps
68    pub fn epsilon() -> Duration {
69        let epsilon = NANOS_PER_SEC / (frequency() as u64);
70        Duration::from_nanos(epsilon)
71    }
72}
73
74/// A timer you can wait on.
75pub(crate) struct WaitableTimer {
76    handle: c::HANDLE,
77}
78
79impl WaitableTimer {
80    /// Creates a high-resolution timer. Will fail before Windows 10, version 1803.
81    pub fn high_resolution() -> Result<Self, ()> {
82        let handle = unsafe {
83            c::CreateWaitableTimerExW(
84                null(),
85                null(),
86                c::CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
87                c::TIMER_ALL_ACCESS,
88            )
89        };
90        if !handle.is_null() { Ok(Self { handle }) } else { Err(()) }
91    }
92
93    pub fn set(&self, duration: Duration) -> Result<(), ()> {
94        // Convert the Duration to a format similar to FILETIME.
95        // Negative values are relative times whereas positive values are absolute.
96        // Therefore we negate the relative duration.
97        let time = checked_dur2intervals(&duration).ok_or(())?.neg();
98        let result = unsafe { c::SetWaitableTimer(self.handle, &time, 0, None, null(), c::FALSE) };
99        if result != 0 { Ok(()) } else { Err(()) }
100    }
101
102    pub fn wait(&self) -> Result<(), ()> {
103        let result = unsafe { c::WaitForSingleObject(self.handle, c::INFINITE) };
104        if result != c::WAIT_FAILED { Ok(()) } else { Err(()) }
105    }
106}
107
108impl Drop for WaitableTimer {
109    fn drop(&mut self) {
110        unsafe { c::CloseHandle(self.handle) };
111    }
112}