1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use crate::{TimerState, Timer};
use core::{time, ptr};
use winapi::shared::minwindef::{FILETIME};
use winapi::um::threadpoolapiset::{
CloseThreadpoolTimer,
CreateThreadpoolTimer,
SetThreadpoolTimerEx,
WaitForThreadpoolTimerCallbacks,
};
use winapi::ctypes::{c_ulong, c_void};
use winapi::um::winnt::{PTP_TIMER_CALLBACK, PTP_CALLBACK_INSTANCE, PTP_TIMER};
unsafe extern "system" fn timer_callback(_: PTP_CALLBACK_INSTANCE, data: *mut c_void, _: PTP_TIMER) {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
let state = data as *mut TimerState;
(*state).wake();
}
unsafe extern "system" fn interval_callback(_: PTP_CALLBACK_INSTANCE, data: *mut c_void, _: PTP_TIMER) {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
let state = data as *mut TimerState;
(*state).wake_by_ref();
}
pub struct WinTimer {
timer: PTP_TIMER,
state: *const TimerState,
}
unsafe impl Send for WinTimer {}
unsafe impl Sync for WinTimer {}
impl WinTimer {
fn init_self(&mut self, cb: PTP_TIMER_CALLBACK) {
if self.timer.is_null() {
self.timer = unsafe {
CreateThreadpoolTimer(cb, self.state as *mut c_void, ptr::null_mut())
};
debug_assert!(!self.timer.is_null());
}
}
fn start(&mut self, time: i64, interval: c_ulong) {
unsafe {
let mut time: FILETIME = core::mem::transmute(time);
SetThreadpoolTimerEx(self.timer, &mut time, interval, 0);
}
}
}
impl Timer for WinTimer {
fn new(state: *const TimerState) -> Self {
Self {
timer: ptr::null_mut(),
state,
}
}
fn reset(&mut self) {
if !self.timer.is_null() {
unsafe {
SetThreadpoolTimerEx(self.timer, ptr::null_mut(), 0, 0);
WaitForThreadpoolTimerCallbacks(self.timer, 1);
CloseThreadpoolTimer(self.timer);
}
self.timer = ptr::null_mut();
}
}
fn start_delay(&mut self, timeout: time::Duration) {
self.init_self(Some(timer_callback));
let mut ticks = i64::from(timeout.subsec_nanos() / 100);
ticks += (timeout.as_secs() * 10_000_000) as i64;
let ticks = -ticks;
self.start(ticks, 0);
}
fn start_interval(&mut self, interval: time::Duration) {
self.init_self(Some(interval_callback));
let mut ticks = i64::from(interval.subsec_nanos() / 100);
ticks += (interval.as_secs() * 10_000_000) as i64;
let millis = (ticks / 10_000) as u32;
let ticks = -ticks;
self.start(ticks, millis);
}
fn state(&self) -> &TimerState {
match unsafe { self.state.as_ref() } {
Some(state) => state,
None => unreach!(),
}
}
}
impl Drop for WinTimer {
fn drop(&mut self) {
self.reset();
}
}