1 // Copyright 2022 The Chromium OS Authors. All rights reserved. 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::{ 6 sync::Arc, 7 time::{Duration, Instant}, 8 }; 9 use sync::Mutex; 10 11 use super::{Event, EventReadResult, FakeClock, RawDescriptor, Result}; 12 use crate::descriptor::{AsRawDescriptor, FromRawDescriptor, IntoRawDescriptor, SafeDescriptor}; 13 14 #[path = "win/timer.rs"] 15 mod timer_platform; 16 17 pub struct Timer { 18 handle: SafeDescriptor, 19 interval: Option<Duration>, 20 } 21 22 impl Timer { 23 /// Creates a new `Timer` instance that shares the same underlying `SafeDescriptor` as the 24 /// existing `Timer` instance. try_clone(&self) -> std::result::Result<Timer, std::io::Error>25 pub fn try_clone(&self) -> std::result::Result<Timer, std::io::Error> { 26 self.handle 27 .try_clone() 28 .map(|handle| Timer { 29 handle, 30 interval: self.interval, 31 }) 32 .map_err(|err| std::io::Error::from_raw_os_error(err.errno())) 33 } 34 } 35 36 // This enum represents those two different retrun values from a "wait" call. Either the 37 // timer will "expire", meaning it has reached it's duration, or the caller will time out 38 // waiting for the timer to expire. If no timeout option is provieded to the wait call 39 // then it can only return WaitResult::Expired or an error. 40 #[derive(PartialEq, Debug)] 41 pub enum WaitResult { 42 Expired, 43 Timeout, 44 } 45 46 impl AsRawDescriptor for Timer { as_raw_descriptor(&self) -> RawDescriptor47 fn as_raw_descriptor(&self) -> RawDescriptor { 48 self.handle.as_raw_descriptor() 49 } 50 } 51 52 impl FromRawDescriptor for Timer { from_raw_descriptor(handle: RawDescriptor) -> Self53 unsafe fn from_raw_descriptor(handle: RawDescriptor) -> Self { 54 Timer { 55 handle: SafeDescriptor::from_raw_descriptor(handle), 56 interval: None, 57 } 58 } 59 } 60 61 impl IntoRawDescriptor for Timer { into_raw_descriptor(self) -> RawDescriptor62 fn into_raw_descriptor(self) -> RawDescriptor { 63 self.handle.into_raw_descriptor() 64 } 65 } 66 67 /// FakeTimer: For use in tests. 68 pub struct FakeTimer { 69 clock: Arc<Mutex<FakeClock>>, 70 deadline_ns: Option<u64>, 71 interval: Option<Duration>, 72 event: Event, 73 } 74 75 impl FakeTimer { 76 /// Creates a new fake Timer. The timer is initally disarmed and must be armed by calling 77 /// `reset`. new(clock: Arc<Mutex<FakeClock>>) -> Self78 pub fn new(clock: Arc<Mutex<FakeClock>>) -> Self { 79 FakeTimer { 80 clock, 81 deadline_ns: None, 82 interval: None, 83 event: Event::new().unwrap(), 84 } 85 } 86 87 /// Sets the timer to expire after `dur`. If `interval` is not `None` it represents 88 /// the period for repeated expirations after the initial expiration. Otherwise 89 /// the timer will expire just once. Cancels any existing duration and repeating interval. reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()>90 pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> { 91 let mut guard = self.clock.lock(); 92 let deadline = guard.nanos() + dur.as_nanos() as u64; 93 self.deadline_ns = Some(deadline); 94 self.interval = interval; 95 guard.add_event(deadline, self.event.try_clone()?); 96 Ok(()) 97 } 98 99 /// Waits until the timer expires, returning WaitResult::Expired when it expires. 100 /// 101 /// If timeout is not None, block for a maximum of the given `timeout` duration. 102 /// If a timeout occurs, return WaitResult::Timeout. wait(&mut self, timeout: Option<Duration>) -> Result<WaitResult>103 pub fn wait(&mut self, timeout: Option<Duration>) -> Result<WaitResult> { 104 let wait_start = Instant::now(); 105 loop { 106 if let Some(timeout) = timeout { 107 let elapsed = Instant::now() - wait_start; 108 if let Some(remaining) = elapsed.checked_sub(timeout) { 109 if let EventReadResult::Timeout = self.event.read_timeout(remaining)? { 110 return Ok(WaitResult::Timeout); 111 } 112 } else { 113 return Ok(WaitResult::Timeout); 114 } 115 } else { 116 self.event.read()?; 117 } 118 119 if let Some(deadline_ns) = &mut self.deadline_ns { 120 let mut guard = self.clock.lock(); 121 let now = guard.nanos(); 122 if now >= *deadline_ns { 123 let mut expirys = 0; 124 if let Some(interval) = self.interval { 125 let interval_ns = interval.as_nanos() as u64; 126 if interval_ns > 0 { 127 expirys += (now - *deadline_ns) / interval_ns; 128 *deadline_ns += (expirys + 1) * interval_ns; 129 guard.add_event(*deadline_ns, self.event.try_clone()?); 130 } 131 } 132 return Ok(WaitResult::Expired); 133 } 134 } 135 } 136 } 137 138 /// After a timer is triggered from an EventContext, mark the timer as having been waited for. 139 /// If a timer is not marked waited, it will immediately trigger the event context again. This 140 /// does not need to be called after calling Timer::wait. 141 /// 142 /// Returns true if the timer has been adjusted since the EventContext was triggered by this 143 /// timer. mark_waited(&mut self) -> Result<bool>144 pub fn mark_waited(&mut self) -> Result<bool> { 145 // Just do a self.wait with a timeout of 0. If it times out then the timer has been 146 // adjusted. 147 if let WaitResult::Timeout = self.wait(Some(Duration::from_secs(0)))? { 148 Ok(true) 149 } else { 150 Ok(false) 151 } 152 } 153 154 /// Disarms the timer. clear(&mut self) -> Result<()>155 pub fn clear(&mut self) -> Result<()> { 156 self.deadline_ns = None; 157 self.interval = None; 158 Ok(()) 159 } 160 161 /// Returns the resolution of timers on the host. resolution() -> Result<Duration>162 pub fn resolution() -> Result<Duration> { 163 Ok(Duration::from_nanos(1)) 164 } 165 } 166 167 impl AsRawDescriptor for FakeTimer { as_raw_descriptor(&self) -> RawDescriptor168 fn as_raw_descriptor(&self) -> RawDescriptor { 169 self.event.as_raw_descriptor() 170 } 171 } 172 impl IntoRawDescriptor for FakeTimer { into_raw_descriptor(self) -> RawDescriptor173 fn into_raw_descriptor(self) -> RawDescriptor { 174 self.event.into_raw_descriptor() 175 } 176 } 177 178 #[cfg(test)] 179 mod tests { 180 use super::*; 181 use std::time::{Duration, Instant}; 182 183 // clock error is 2*clock_resolution + 100 microseconds to handle 184 // time change from calling now() to arming timer get_clock_error() -> Duration185 fn get_clock_error() -> Duration { 186 Timer::resolution() 187 .expect("expected to be able to read timer resolution") 188 .checked_mul(2) 189 .expect("timer resolution x 2 should not overflow") 190 .checked_add(Duration::from_micros(100)) 191 .expect("timer resolution x 2 + 100 microsecond should not overflow") 192 } 193 194 #[test] 195 #[ignore] one_shot()196 fn one_shot() { 197 // This test relies on the host having a reliable clock and not being 198 // overloaded, so it's marked as "ignore". You can run by running 199 // cargo test -p win_sys_util timer -- --ignored 200 201 let mut tfd = Timer::new().expect("failed to create Timer"); 202 203 let dur = Duration::from_millis(1000); 204 let clock_error = get_clock_error(); 205 206 let now = Instant::now(); 207 tfd.reset(dur, None).expect("failed to arm timer"); 208 209 tfd.wait(None).expect("unable to wait for timer"); 210 let elapsed = now.elapsed(); 211 // elapsed is within +-clock_error from expected duration 212 assert!(elapsed - clock_error <= dur); 213 assert!(elapsed + clock_error >= dur); 214 } 215 216 /// Similar to one_shot, except this one waits for a clone of the timer. 217 #[test] 218 #[ignore] one_shot_cloned()219 fn one_shot_cloned() { 220 let mut tfd = Timer::new().expect("failed to create Timer"); 221 let dur = Duration::from_millis(1000); 222 let mut cloned_tfd = tfd.try_clone().expect("failed to clone timer"); 223 224 // clock error is 2*clock_resolution + 100 microseconds to handle 225 // time change from calling now() to arming timer 226 let clock_error = get_clock_error(); 227 228 let now = Instant::now(); 229 tfd.reset(dur, None).expect("failed to arm timer"); 230 cloned_tfd.wait(None).expect("unable to wait for timer"); 231 let elapsed = now.elapsed(); 232 233 // elapsed is within +-clock_error from expected duration 234 assert!(elapsed - clock_error <= dur); 235 assert!(elapsed + clock_error >= dur); 236 } 237 238 #[test] 239 #[ignore] repeating()240 fn repeating() { 241 // This test relies on the host having a reliable clock and not being 242 // overloaded, so it's marked as "ignore". You can run by running 243 // cargo test -p win_sys_util timer -- --ignored 244 245 let mut tfd = Timer::new().expect("failed to create Timer"); 246 247 let dur = Duration::from_millis(200); 248 // clock error is 2*clock_resolution + 100 microseconds to handle 249 // time change from calling now() to arming timer 250 let clock_error = Timer::resolution() 251 .expect("expected to be able to read timer resolution") 252 .checked_mul(2) 253 .expect("timer resolution x 2 should not overflow") 254 .checked_add(Duration::from_micros(100)) 255 .expect("timer resolution x 2 + 100 microsecond should not overflow"); 256 let interval = Duration::from_millis(100); 257 let now = Instant::now(); 258 tfd.reset(dur, Some(interval)).expect("failed to arm timer"); 259 260 tfd.wait(None).expect("unable to wait for timer"); 261 // should take "dur" duration for the first wait 262 assert!(now.elapsed() + clock_error >= dur); 263 tfd.wait(None).expect("unable to wait for timer"); 264 // subsequent waits should take "interval" duration 265 assert!(now.elapsed() + clock_error >= dur + interval); 266 tfd.wait(None).expect("unable to wait for timer"); 267 assert!(now.elapsed() + clock_error >= dur + interval * 2); 268 } 269 270 #[test] fake_one_shot()271 fn fake_one_shot() { 272 let clock = Arc::new(Mutex::new(FakeClock::new())); 273 let mut tfd = FakeTimer::new(clock.clone()); 274 275 let dur = Duration::from_nanos(200); 276 tfd.reset(dur, None).expect("failed to arm timer"); 277 278 clock.lock().add_ns(200); 279 280 let result = tfd.wait(None).expect("unable to wait for timer"); 281 282 assert_eq!(result, WaitResult::Expired); 283 } 284 285 #[test] fake_one_shot_timeout()286 fn fake_one_shot_timeout() { 287 let clock = Arc::new(Mutex::new(FakeClock::new())); 288 let mut tfd = FakeTimer::new(clock.clone()); 289 290 let dur = Duration::from_nanos(200); 291 tfd.reset(dur, None).expect("failed to arm timer"); 292 293 clock.lock().add_ns(100); 294 let result = tfd 295 .wait(Some(Duration::from_millis(0))) 296 .expect("unable to wait for timer"); 297 assert_eq!(result, WaitResult::Timeout); 298 let result = tfd 299 .wait(Some(Duration::from_millis(1))) 300 .expect("unable to wait for timer"); 301 assert_eq!(result, WaitResult::Timeout); 302 303 clock.lock().add_ns(100); 304 let result = tfd 305 .wait(Some(Duration::from_millis(0))) 306 .expect("unable to wait for timer"); 307 assert_eq!(result, WaitResult::Expired); 308 } 309 310 #[test] fake_repeating()311 fn fake_repeating() { 312 let clock = Arc::new(Mutex::new(FakeClock::new())); 313 let mut tfd = FakeTimer::new(clock.clone()); 314 315 let dur = Duration::from_nanos(200); 316 let interval = Duration::from_nanos(100); 317 tfd.reset(dur, Some(interval)).expect("failed to arm timer"); 318 319 clock.lock().add_ns(300); 320 321 let mut result = tfd.wait(None).expect("unable to wait for timer"); 322 // An expiration from the initial expiry and from 1 repeat. 323 assert_eq!(result, WaitResult::Expired); 324 325 clock.lock().add_ns(300); 326 result = tfd.wait(None).expect("unable to wait for timer"); 327 assert_eq!(result, WaitResult::Expired); 328 } 329 330 #[test] 331 #[ignore] zero_interval()332 fn zero_interval() { 333 // This test relies on the host having a reliable clock and not being 334 // overloaded, so it's marked as "ignore". You can run by running 335 // cargo test -p win_sys_util timer -- --ignored 336 337 let mut tfd = Timer::new().expect("failed to create timer"); 338 339 let dur = Duration::from_nanos(200); 340 // interval is 0, so should not repeat 341 let interval = Duration::from_nanos(0); 342 343 tfd.reset(dur, Some(interval)).expect("failed to arm timer"); 344 345 // should wait successfully the first time 346 tfd.wait(None).expect("unable to wait for timer"); 347 348 // now this wait should timeout 349 let wr = tfd 350 .wait(Some(Duration::from_secs(1))) 351 .expect("unable to wait on timer"); 352 353 assert_eq!(wr, WaitResult::Timeout); 354 } 355 } 356