std\sys\pal\windows/
time.rs1use 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 static FREQUENCY: AtomicI64 = AtomicI64::new(0);
39
40 let cached = FREQUENCY.load(Ordering::Relaxed);
41 if cached != 0 {
43 return cached;
44 }
45 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 unsafe { crate::hint::assert_unchecked(frequency != 0) }
59
60 cache.store(frequency, Ordering::Relaxed);
61 frequency
62 }
63
64 pub fn epsilon() -> Duration {
69 let epsilon = NANOS_PER_SEC / (frequency() as u64);
70 Duration::from_nanos(epsilon)
71 }
72}
73
74pub(crate) struct WaitableTimer {
76 handle: c::HANDLE,
77}
78
79impl WaitableTimer {
80 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 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}