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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
//! Windows timers API
use crate::sys::{
QueryPerformanceFrequency,
QueryPerformanceCounter,
LARGE_INTEGER,
CreateTimerQueue,
CreateTimerQueueTimer,
DeleteTimerQueueEx,
DeleteTimerQueueTimer,
ChangeTimerQueueTimer,
HANDLE,
INVALID_HANDLE_VALUE,
WT_EXECUTEINTIMERTHREAD,
WT_EXECUTEINPERSISTENTTHREAD,
WT_EXECUTELONGFUNCTION,
WT_EXECUTEONLYONCE,
WT_TRANSFER_IMPERSONATION,
WAITORTIMERCALLBACK,
c_int,
c_ulong,
c_void,
};
use crate::utils::{self, Result};
use core::{ptr, mem};
///Retrieves the frequency of the performance counter.
///
///The frequency of the performance counter is fixed at system boot and is consistent across all processors.
///Therefore, the frequency need only be queried upon application initialization, and the result can be cached.
pub fn query_performance_frequency() -> Result<i64> {
let mut counter: LARGE_INTEGER = unsafe { mem::zeroed() };
unsafe {
match QueryPerformanceFrequency(&mut counter as *mut _) {
0 => Err(utils::get_last_error()),
_ => Ok(counter.QuadPart)
}
}
}
///Retrieves the current value of the performance counter, which is a high resolution (<1us) time
///stamp that can be used for time-interval measurements.
pub fn query_performance_counter() -> Result<i64> {
let mut counter: LARGE_INTEGER = unsafe { mem::zeroed() };
unsafe {
match QueryPerformanceCounter(&mut counter as *mut _) {
0 => Err(utils::get_last_error()),
_ => Ok(counter.QuadPart)
}
}
}
///Describes how to delete timer/queue
pub trait CompleteEvent {
#[doc(hidden)]
fn handle() -> HANDLE;
}
///Schedules delete and exit immediately
pub struct NoWait;
impl CompleteEvent for NoWait {
fn handle() -> HANDLE {
ptr::null_mut()
}
}
///Waits for all callback functions to finish
pub struct Wait;
impl CompleteEvent for Wait {
fn handle() -> HANDLE {
INVALID_HANDLE_VALUE
}
}
#[derive(Copy, Clone)]
///Describes timer flags
pub struct TimerFlags {
inner: c_ulong
}
///Default timer flags to only execute callback on non-IO thread
pub const DEFAULT_TIMER_FLAGS: TimerFlags = TimerFlags {
inner: 0
};
impl TimerFlags {
///Creates new instance of default flags
pub fn new() -> Self {
DEFAULT_TIMER_FLAGS
}
///The callback function is invoked by the timer thread itself.
///
///This flag should be used only for short tasks or it could affect other timer operations.
pub fn on_timer_thread(mut self) -> Self {
self.inner |= WT_EXECUTEINTIMERTHREAD;
self
}
///The callback function is queued to a thread that never terminates.
///
///It does not guarantee that the same thread is used each time.
///This flag should be used only for short tasks or it could affect other timer operations.
pub fn on_persist(mut self) -> Self {
self.inner |= WT_EXECUTEINPERSISTENTTHREAD;
self
}
///The callback function can perform a long wait.
///
///This flag helps the system to decide if it should create a new thread.
pub fn long_fn(mut self) -> Self {
self.inner |= WT_EXECUTELONGFUNCTION;
self
}
///The timer will be set to the signaled state only once.
///
///If this flag is set, the Period parameter must not be set.
pub fn only_once(mut self) -> Self {
self.inner |= WT_EXECUTEONLYONCE;
self
}
///Callback functions will use the current access token, whether it is a process or
///impersonation token.
///
///If this flag is not specified, callback functions execute only with the
///process token.
pub fn transfer_impersonation(mut self) -> Self {
self.inner |= WT_TRANSFER_IMPERSONATION;
self
}
}
///Queue for timer
///
///By default `Drop` implementation deletes timer without waiting for
///queue to finish currently executing callbacks.
///If you want to wait then you can use `delete` method.
///
///Alternatively you can use default system queue by accessing `DEFAULT_TIMER_QUEUE`
///In this case it is impossible to delete queue and `delete` always returns `Ok`
pub struct TimerQueue {
handle: HANDLE
}
impl TimerQueue {
///Creates new instance of queue
pub fn new() -> Result<Self> {
let handle = unsafe { CreateTimerQueue() };
match handle.is_null() {
true => Err(utils::get_last_error()),
false => Ok(Self { handle })
}
}
#[inline]
fn inner_delete<T: CompleteEvent>(&self) -> c_int {
match self.handle.is_null() {
true => 1,
false => unsafe { DeleteTimerQueueEx(self.handle, T::handle()) },
}
}
///Deletes queue and consumes it.
///
///Note that it invalidates all timers produced by it.
pub fn delete<T: CompleteEvent>(self, _event: T) -> Result<()> {
let result = match self.inner_delete::<T>() {
0 => Err(utils::get_last_error()),
_ => Ok(())
};
mem::forget(self);
result
}
///Creates new timer on queue.
///
///## Parameters
///
///- `cb` - C function to be executed.
///- `param` - Pointer to callback parameter.
///- `due_time` - The amount of time in milliseconds relative to the current time that must elapse before the timer is signaled for the first time.
///- `period` - The period of the timer, in milliseconds. If this parameter is zero, the timer is signaled once. If this parameter is greater than zero, the timer is periodic. A periodic timer automatically reactivates each time the period elapses, until the timer is canceled.
///- `flags` - Timer flags
pub fn timer(&self, cb: WAITORTIMERCALLBACK, param: *mut c_void, due_time: c_ulong, period: c_ulong, flags: TimerFlags) -> Result<QueueTimer> {
let mut timer: *mut c_void = ptr::null_mut();
match unsafe { CreateTimerQueueTimer(&mut timer as *mut _, self.handle, cb, param, due_time, period, flags.inner) } {
0 => Err(utils::get_last_error()),
_ => Ok(QueueTimer { queue: self.handle, inner: timer })
}
}
}
///Raw type of callback function
pub type CallbackType = WAITORTIMERCALLBACK;
///Default Timer queue
pub const DEFAULT_TIMER_QUEUE: TimerQueue = TimerQueue {
handle: ptr::null_mut()
};
impl Default for TimerQueue {
fn default() -> Self {
DEFAULT_TIMER_QUEUE
}
}
impl Drop for TimerQueue {
fn drop(&mut self) {
let _ = self.inner_delete::<NoWait>();
}
}
unsafe impl Send for TimerQueue {}
unsafe impl Sync for TimerQueue {}
///Timer that schedules callback on thread pool
///
///By default `Drop` implementation deletes queue without waiting for
///callback to be finished.
///If you want to wait then you can use `delete` method.
pub struct QueueTimer {
queue: HANDLE,
inner: HANDLE,
}
impl QueueTimer {
#[inline]
fn inner_delete<T: CompleteEvent>(&self) -> c_int {
unsafe { DeleteTimerQueueTimer(self.queue, self.inner, T::handle()) }
}
///Cancels timer without consuming it
///
///User must ensure that drop is not called by forgetting timer
pub unsafe fn cancel<T: CompleteEvent>(&self, _event: T) -> Result<()> {
match self.inner_delete::<T>() {
0 => Err(utils::get_last_error()),
_ => Ok(())
}
}
///Resets timer with new values of due_time and period
///
///Note: if you call it on a one-shot timer (its period is zero) that has already expired, the timer is not
///updated.
pub fn reset(&self, due_time: c_ulong, period: c_ulong) -> Result<()> {
match unsafe { ChangeTimerQueueTimer(self.queue, self.inner, due_time, period) } {
0 => Err(utils::get_last_error()),
_ => Ok(())
}
}
///Deletes timer and consumes it.
pub fn delete<T: CompleteEvent>(self, event: T) -> Result<()> {
let result = unsafe { self.cancel(event) };
mem::forget(self);
result
}
}
impl Drop for QueueTimer {
fn drop(&mut self) {
let _ = self.inner_delete::<NoWait>();
}
}
unsafe impl Send for QueueTimer {}
unsafe impl Sync for QueueTimer {}