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