// Copyright 2020 The ChromiumOS Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. use std::sync::Arc; use std::time::Duration; use std::time::Instant; use sync::Mutex; use super::Event; use super::EventWaitResult; use super::FakeClock; use super::RawDescriptor; use super::Result; use crate::descriptor::AsRawDescriptor; use crate::descriptor::FromRawDescriptor; use crate::descriptor::IntoRawDescriptor; use crate::descriptor::SafeDescriptor; /// A trait for timer objects that delivers timer expiration /// notifications to an underlying descriptor. pub trait TimerTrait: AsRawDescriptor + IntoRawDescriptor + Send { /// Sets the timer to expire after `dur` without repeating. Cancels any existing timer. fn reset_oneshot(&mut self, dur: Duration) -> Result<()>; /// Sets the timer to fire repeatedly at `dur` intervals. Cancels any existing timer. fn reset_repeating(&mut self, dur: Duration) -> Result<()>; /// Waits until the timer expires. fn wait(&mut self) -> Result<()>; /// After a timer is triggered from an EventContext, mark the timer as having been waited for. /// If a timer is not marked waited, it will immediately trigger the event context again. This /// does not need to be called after calling Timer::wait. /// /// Returns true if the timer has been adjusted since the EventContext was triggered by this /// timer. fn mark_waited(&mut self) -> Result; /// Disarms the timer. fn clear(&mut self) -> Result<()>; /// Returns the resolution of timers on the host. fn resolution(&self) -> Result; } pub struct Timer { pub(crate) handle: SafeDescriptor, pub(crate) interval: Option, } impl Timer { /// Creates a new `Timer` instance that shares the same underlying `SafeDescriptor` as the /// existing `Timer` instance. pub fn try_clone(&self) -> std::result::Result { self.handle .try_clone() .map(|handle| Timer { handle, interval: self.interval, }) .map_err(|err| std::io::Error::from_raw_os_error(err.errno())) } } // This enum represents those two different retrun values from a "wait" call. Either the // timer will "expire", meaning it has reached it's duration, or the caller will time out // waiting for the timer to expire. If no timeout option is provieded to the wait call // then it can only return WaitResult::Expired or an error. #[derive(PartialEq, Eq, Debug)] enum WaitResult { Expired, Timeout, } impl AsRawDescriptor for Timer { fn as_raw_descriptor(&self) -> RawDescriptor { self.handle.as_raw_descriptor() } } impl FromRawDescriptor for Timer { unsafe fn from_raw_descriptor(handle: RawDescriptor) -> Self { Timer { handle: SafeDescriptor::from_raw_descriptor(handle), interval: None, } } } impl IntoRawDescriptor for Timer { fn into_raw_descriptor(self) -> RawDescriptor { self.handle.into_raw_descriptor() } } /// FakeTimer: For use in tests. pub struct FakeTimer { clock: Arc>, deadline_ns: Option, interval: Option, event: Event, } impl FakeTimer { /// Creates a new fake Timer. The timer is initally disarmed and must be armed by calling /// `reset`. pub fn new(clock: Arc>) -> Self { FakeTimer { clock, deadline_ns: None, interval: None, event: Event::new().unwrap(), } } fn reset(&mut self, dur: Duration) -> Result<()> { let mut guard = self.clock.lock(); let deadline = guard.nanos() + dur.as_nanos() as u64; self.deadline_ns = Some(deadline); guard.add_event(deadline, self.event.try_clone()?); Ok(()) } /// Waits until the timer expires or an optional wait timeout expires, whichever happens first. /// /// # Returns /// /// - `WaitResult::Expired` if the timer expired. /// - `WaitResult::Timeout` if `timeout` was not `None` and the timer did not expire within the /// specified timeout period. fn wait_for(&mut self, timeout: Option) -> Result { let wait_start = Instant::now(); loop { if let Some(timeout) = timeout { let elapsed = Instant::now() - wait_start; if let Some(remaining) = elapsed.checked_sub(timeout) { if let EventWaitResult::TimedOut = self.event.wait_timeout(remaining)? { return Ok(WaitResult::Timeout); } } else { return Ok(WaitResult::Timeout); } } else { self.event.wait()?; } if let Some(deadline_ns) = &mut self.deadline_ns { let mut guard = self.clock.lock(); let now = guard.nanos(); if now >= *deadline_ns { let mut expirys = 0; if let Some(interval) = self.interval { let interval_ns = interval.as_nanos() as u64; if interval_ns > 0 { expirys += (now - *deadline_ns) / interval_ns; *deadline_ns += (expirys + 1) * interval_ns; guard.add_event(*deadline_ns, self.event.try_clone()?); } } return Ok(WaitResult::Expired); } } } } } impl TimerTrait for FakeTimer { fn reset_oneshot(&mut self, dur: Duration) -> Result<()> { self.interval = None; self.reset(dur) } fn reset_repeating(&mut self, dur: Duration) -> Result<()> { self.interval = Some(dur); self.reset(dur) } fn wait(&mut self) -> Result<()> { self.wait_for(None).map(|_| ()) } fn mark_waited(&mut self) -> Result { // Just do a self.wait with a timeout of 0. If it times out then the timer has been // adjusted. if let WaitResult::Timeout = self.wait_for(Some(Duration::from_secs(0)))? { Ok(true) } else { Ok(false) } } fn clear(&mut self) -> Result<()> { self.deadline_ns = None; self.interval = None; Ok(()) } fn resolution(&self) -> Result { Ok(Duration::from_nanos(1)) } } impl AsRawDescriptor for FakeTimer { fn as_raw_descriptor(&self) -> RawDescriptor { self.event.as_raw_descriptor() } } impl IntoRawDescriptor for FakeTimer { fn into_raw_descriptor(self) -> RawDescriptor { self.event.into_raw_descriptor() } } #[cfg(test)] mod tests { use std::time::Duration; use std::time::Instant; use super::*; use crate::EventToken; use crate::WaitContext; #[test] fn one_shot() { let mut tfd = Timer::new().expect("failed to create Timer"); let dur = Duration::from_millis(10); let now = Instant::now(); tfd.reset_oneshot(dur).expect("failed to arm timer"); tfd.wait().expect("unable to wait for timer"); let elapsed = now.elapsed(); assert!(elapsed >= dur, "expected {:?} >= {:?}", elapsed, dur); } /// Similar to one_shot, except this one waits for a clone of the timer. #[test] fn one_shot_cloned() { let mut tfd = Timer::new().expect("failed to create Timer"); let mut cloned_tfd = tfd.try_clone().expect("failed to clone timer"); let dur = Duration::from_millis(10); let now = Instant::now(); tfd.reset_oneshot(dur).expect("failed to arm timer"); cloned_tfd.wait().expect("unable to wait for timer"); let elapsed = now.elapsed(); assert!(elapsed >= dur, "expected {:?} >= {:?}", elapsed, dur); } #[test] fn repeating() { let mut tfd = Timer::new().expect("failed to create Timer"); let interval = Duration::from_millis(10); let now = Instant::now(); tfd.reset_repeating(interval).expect("failed to arm timer"); tfd.wait().expect("unable to wait for timer"); // should take `interval` duration for the first wait assert!(now.elapsed() >= interval); tfd.wait().expect("unable to wait for timer"); // subsequent waits should take "interval" duration assert!(now.elapsed() >= interval * 2); tfd.wait().expect("unable to wait for timer"); assert!(now.elapsed() >= interval * 3); } #[test] fn mark_waited_inactive() { let mut tfd = Timer::new().expect("failed to create Timer"); // This ought to return true, but Windows always returns false, so we can't assert it here. tfd.mark_waited().expect("mark_waited failed"); } #[test] fn mark_waited_active() { let mut tfd = Timer::new().expect("failed to create Timer"); tfd.reset_oneshot(Duration::from_nanos(1)) .expect("failed to arm timer"); // Use a WaitContext to block until the timer has fired. #[derive(EventToken)] enum Token { Timer, } let wait_ctx: WaitContext = WaitContext::build_with(&[(&tfd, Token::Timer)]).unwrap(); let _events = wait_ctx.wait().unwrap(); assert!( !tfd.mark_waited().expect("mark_waited failed"), "expected mark_waited to return false", ); } #[test] fn fake_one_shot() { let clock = Arc::new(Mutex::new(FakeClock::new())); let mut tfd = FakeTimer::new(clock.clone()); let dur = Duration::from_nanos(200); tfd.reset_oneshot(dur).expect("failed to arm timer"); clock.lock().add_ns(200); assert_eq!(tfd.wait().is_ok(), true); } #[test] fn fake_one_shot_timeout() { let clock = Arc::new(Mutex::new(FakeClock::new())); let mut tfd = FakeTimer::new(clock.clone()); let dur = Duration::from_nanos(200); tfd.reset_oneshot(dur).expect("failed to arm timer"); clock.lock().add_ns(100); let result = tfd .wait_for(Some(Duration::from_millis(0))) .expect("unable to wait for timer"); assert_eq!(result, WaitResult::Timeout); let result = tfd .wait_for(Some(Duration::from_millis(1))) .expect("unable to wait for timer"); assert_eq!(result, WaitResult::Timeout); clock.lock().add_ns(100); let result = tfd .wait_for(Some(Duration::from_millis(0))) .expect("unable to wait for timer"); assert_eq!(result, WaitResult::Expired); } #[test] fn fake_repeating() { let clock = Arc::new(Mutex::new(FakeClock::new())); let mut tfd = FakeTimer::new(clock.clone()); let interval = Duration::from_nanos(100); tfd.reset_repeating(interval).expect("failed to arm timer"); clock.lock().add_ns(150); // An expiration from the initial expiry and from 1 repeat. assert_eq!(tfd.wait().is_ok(), true); clock.lock().add_ns(100); assert_eq!(tfd.wait().is_ok(), true); } }