• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::os::windows::io::AsRawHandle;
6 use std::os::windows::io::RawHandle;
7 use std::ptr;
8 use std::time::Duration;
9 
10 use win_util::LargeInteger;
11 use win_util::SecurityAttributes;
12 use win_util::SelfRelativeSecurityDescriptor;
13 use winapi::shared::minwindef::FALSE;
14 use winapi::um::synchapi::CancelWaitableTimer;
15 use winapi::um::synchapi::SetWaitableTimer;
16 use winapi::um::synchapi::WaitForSingleObject;
17 use winapi::um::winbase::CreateWaitableTimerA;
18 use winapi::um::winbase::INFINITE;
19 use winapi::um::winbase::WAIT_OBJECT_0;
20 
21 use super::errno_result;
22 use super::platform_timer_utils::nt_query_timer_resolution;
23 use super::Result;
24 use crate::descriptor::AsRawDescriptor;
25 use crate::descriptor::FromRawDescriptor;
26 use crate::descriptor::SafeDescriptor;
27 use crate::timer::Timer;
28 use crate::timer::TimerTrait;
29 
30 impl AsRawHandle for Timer {
as_raw_handle(&self) -> RawHandle31     fn as_raw_handle(&self) -> RawHandle {
32         self.handle.as_raw_descriptor()
33     }
34 }
35 
36 impl Timer {
37     /// Creates a new timer.  The timer is initally disarmed and must be armed by calling
38     /// `reset`. Note that this timer MAY wake/trigger early due to limitations on
39     /// SetWaitableTimer (see <https://github.com/rust-lang/rust/issues/43376>).
new() -> Result<Timer>40     pub fn new() -> Result<Timer> {
41         // SAFETY:
42         // Safe because this doesn't modify any memory and we check the return value.
43         let handle = unsafe {
44             CreateWaitableTimerA(
45                 // Not inheritable, duplicate before passing to child prcesses
46                 SecurityAttributes::new_with_security_descriptor(
47                     SelfRelativeSecurityDescriptor::get_singleton(),
48                     /* inherit= */ false,
49                 )
50                 .as_mut(),
51                 // This is a synchronization timer, not a manual-reset timer.
52                 FALSE,
53                 // TODO (colindr) b/145622516 - we may have to give this a name if we later
54                 // want to use names to test object equality
55                 ptr::null_mut(),
56             )
57         };
58 
59         if handle.is_null() {
60             return errno_result();
61         }
62 
63         Ok(Timer {
64             // SAFETY:
65             // Safe because we uniquely own the file descriptor.
66             handle: unsafe { SafeDescriptor::from_raw_descriptor(handle) },
67             interval: None,
68         })
69     }
70 }
71 
72 impl TimerTrait for Timer {
reset(&mut self, dur: Duration, mut interval: Option<Duration>) -> Result<()>73     fn reset(&mut self, dur: Duration, mut interval: Option<Duration>) -> Result<()> {
74         // If interval is 0 or None it means that this timer does not repeat. We
75         // set self.interval to None in this case so it can easily be checked
76         // in self.wait.
77         if interval == Some(Duration::from_secs(0)) {
78             interval = None;
79         }
80         self.interval = interval;
81         // Windows timers use negative values for relative times, and positive
82         // values for absolute times, so we'll use negative times.
83 
84         // Windows timers also use a 64 number of 100 nanosecond intervals,
85         // which we get like so: (dur.as_secs()*1e7 + dur.subsec_nanos()/100)
86 
87         let due_time = LargeInteger::new(
88             -((dur.as_secs() * 10_000_000 + (dur.subsec_nanos() as u64) / 100) as i64),
89         );
90         let period: i32 = match interval {
91             Some(int) => {
92                 if int.is_zero() {
93                     // Duration of zero implies non-periodic, which means setting period
94                     // to 0ms.
95                     0
96                 } else {
97                     // Otherwise, convert to ms and make sure it's >=1ms.
98                     std::cmp::max(1, int.as_millis() as i32)
99                 }
100             }
101             // Period of 0ms=non-periodic.
102             None => 0,
103         };
104 
105         // SAFETY:
106         // Safe because this doesn't modify any memory and we check the return value.
107         let ret = unsafe {
108             SetWaitableTimer(
109                 self.as_raw_descriptor(),
110                 &*due_time,
111                 period,
112                 None,            // no completion routine
113                 ptr::null_mut(), // or routine argument
114                 FALSE,           // no restoring system from power conservation mode
115             )
116         };
117         if ret == 0 {
118             return errno_result();
119         }
120 
121         Ok(())
122     }
123 
wait(&mut self) -> Result<()>124     fn wait(&mut self) -> Result<()> {
125         // SAFETY:
126         // Safe because this doesn't modify any memory and we check the return value.
127         let ret = unsafe { WaitForSingleObject(self.as_raw_descriptor(), INFINITE) };
128 
129         // Should return WAIT_OBJECT_0, otherwise it's some sort of error or
130         // timeout (which shouldn't happen in this case).
131         match ret {
132             WAIT_OBJECT_0 => Ok(()),
133             _ => errno_result(),
134         }
135     }
136 
mark_waited(&mut self) -> Result<bool>137     fn mark_waited(&mut self) -> Result<bool> {
138         // We use a synchronization timer on windows, meaning waiting on the timer automatically
139         // un-signals the timer. We assume this is atomic so the return value is always false.
140         Ok(false)
141     }
142 
clear(&mut self) -> Result<()>143     fn clear(&mut self) -> Result<()> {
144         // SAFETY:
145         // Safe because this doesn't modify any memory and we check the return value.
146         let ret = unsafe { CancelWaitableTimer(self.as_raw_descriptor()) };
147 
148         if ret == 0 {
149             return errno_result();
150         }
151 
152         self.interval = None;
153         Ok(())
154     }
155 
resolution(&self) -> Result<Duration>156     fn resolution(&self) -> Result<Duration> {
157         nt_query_timer_resolution().map(|(current_res, _)| current_res)
158     }
159 }
160