// Copyright 2022 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use std::os::windows::io::AsRawHandle;5use std::os::windows::io::RawHandle;6use std::ptr;7use std::time::Duration;89use win_util::LargeInteger;10use win_util::SecurityAttributes;11use win_util::SelfRelativeSecurityDescriptor;12use winapi::shared::minwindef::FALSE;13use winapi::um::synchapi::CancelWaitableTimer;14use winapi::um::synchapi::SetWaitableTimer;15use winapi::um::synchapi::WaitForSingleObject;16use winapi::um::winbase::CreateWaitableTimerA;17use winapi::um::winbase::INFINITE;18use winapi::um::winbase::WAIT_OBJECT_0;1920use super::errno_result;21use super::platform_timer_utils::nt_query_timer_resolution;22use super::Result;23use crate::descriptor::AsRawDescriptor;24use crate::descriptor::FromRawDescriptor;25use crate::descriptor::SafeDescriptor;26use crate::timer::Timer;27use crate::timer::TimerTrait;2829impl AsRawHandle for Timer {30fn as_raw_handle(&self) -> RawHandle {31self.handle.as_raw_descriptor()32}33}3435impl Timer {36/// Creates a new timer. The timer is initally disarmed and must be armed by calling37/// `reset`. Note that this timer MAY wake/trigger early due to limitations on38/// SetWaitableTimer (see <https://github.com/rust-lang/rust/issues/43376>).39pub fn new() -> Result<Timer> {40// SAFETY:41// Safe because this doesn't modify any memory and we check the return value.42let handle = unsafe {43CreateWaitableTimerA(44// Not inheritable, duplicate before passing to child prcesses45SecurityAttributes::new_with_security_descriptor(46SelfRelativeSecurityDescriptor::get_singleton(),47/* inherit= */ false,48)49.as_mut(),50// This is a synchronization timer, not a manual-reset timer.51FALSE,52// TODO (colindr) b/145622516 - we may have to give this a name if we later53// want to use names to test object equality54ptr::null_mut(),55)56};5758if handle.is_null() {59return errno_result();60}6162Ok(Timer {63// SAFETY:64// Safe because we uniquely own the file descriptor.65handle: unsafe { SafeDescriptor::from_raw_descriptor(handle) },66interval: None,67})68}6970fn reset(&mut self, dur: Duration, mut interval: Option<Duration>) -> Result<()> {71// If interval is 0 or None it means that this timer does not repeat. We72// set self.interval to None in this case so it can easily be checked73// in self.wait.74if interval == Some(Duration::from_secs(0)) {75interval = None;76}77self.interval = interval;78// Windows timers use negative values for relative times, and positive79// values for absolute times, so we'll use negative times.8081// Windows timers also use a 64 number of 100 nanosecond intervals,82// which we get like so: (dur.as_secs()*1e7 + dur.subsec_nanos()/100)8384let due_time = LargeInteger::new(85-((dur.as_secs() * 10_000_000 + (dur.subsec_nanos() as u64) / 100) as i64),86);87let period: i32 = match interval {88Some(int) => {89if int.is_zero() {90// Duration of zero implies non-periodic, which means setting period91// to 0ms.92093} else {94// Otherwise, convert to ms and make sure it's >=1ms.95std::cmp::max(1, int.as_millis() as i32)96}97}98// Period of 0ms=non-periodic.99None => 0,100};101102// SAFETY:103// Safe because this doesn't modify any memory and we check the return value.104let ret = unsafe {105SetWaitableTimer(106self.as_raw_descriptor(),107&*due_time,108period,109None, // no completion routine110ptr::null_mut(), // or routine argument111FALSE, // no restoring system from power conservation mode112)113};114if ret == 0 {115return errno_result();116}117118Ok(())119}120}121122impl TimerTrait for Timer {123fn reset_oneshot(&mut self, dur: Duration) -> Result<()> {124self.reset(dur, None)125}126127fn reset_repeating(&mut self, interval: Duration) -> Result<()> {128self.reset(interval, Some(interval))129}130131fn wait(&mut self) -> Result<()> {132// SAFETY:133// Safe because this doesn't modify any memory and we check the return value.134let ret = unsafe { WaitForSingleObject(self.as_raw_descriptor(), INFINITE) };135136// Should return WAIT_OBJECT_0, otherwise it's some sort of error or137// timeout (which shouldn't happen in this case).138match ret {139WAIT_OBJECT_0 => Ok(()),140_ => errno_result(),141}142}143144fn mark_waited(&mut self) -> Result<bool> {145// We use a synchronization timer on windows, meaning waiting on the timer automatically146// un-signals the timer. We assume this is atomic so the return value is always false.147Ok(false)148}149150fn clear(&mut self) -> Result<()> {151// SAFETY:152// Safe because this doesn't modify any memory and we check the return value.153let ret = unsafe { CancelWaitableTimer(self.as_raw_descriptor()) };154155if ret == 0 {156return errno_result();157}158159self.interval = None;160Ok(())161}162163fn resolution(&self) -> Result<Duration> {164nt_query_timer_resolution().map(|(current_res, _)| current_res)165}166}167168169