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