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