1 // Copyright 2018 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 fs::File, 7 mem, 8 os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}, 9 ptr, 10 sync::Arc, 11 time::Duration, 12 }; 13 use sync::Mutex; 14 15 use libc::{self, clock_getres, timerfd_create, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC}; 16 17 use super::{errno_result, EventFd, FakeClock, Result}; 18 19 /// A safe wrapper around a Linux timerfd (man 2 timerfd_create). 20 pub struct TimerFd(File); 21 22 impl TimerFd { 23 /// Creates a new timerfd. The timer is initally disarmed and must be armed by calling 24 /// `reset`. new() -> Result<TimerFd>25 pub fn new() -> Result<TimerFd> { 26 // Safe because this doesn't modify any memory and we check the return value. 27 let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC) }; 28 if ret < 0 { 29 return errno_result(); 30 } 31 32 // Safe because we uniquely own the file descriptor. 33 Ok(TimerFd(unsafe { File::from_raw_fd(ret) })) 34 } 35 36 /// Creates a new `TimerFd` instance that shares the same underlying `File` as the existing 37 /// `TimerFd` instance. try_clone(&self) -> std::result::Result<TimerFd, std::io::Error>38 pub fn try_clone(&self) -> std::result::Result<TimerFd, std::io::Error> { 39 self.0.try_clone().map(TimerFd) 40 } 41 42 /// Sets the timer to expire after `dur`. If `interval` is not `None` it represents 43 /// the period for repeated expirations after the initial expiration. Otherwise 44 /// the timer will expire just once. Cancels any existing duration and repeating interval. reset(&self, dur: Duration, interval: Option<Duration>) -> Result<()>45 pub fn reset(&self, dur: Duration, interval: Option<Duration>) -> Result<()> { 46 // Safe because we are zero-initializing a struct with only primitive member fields. 47 let mut spec: libc::itimerspec = unsafe { mem::zeroed() }; 48 spec.it_value.tv_sec = dur.as_secs() as libc::time_t; 49 // nsec always fits in i32 because subsec_nanos is defined to be less than one billion. 50 let nsec = dur.subsec_nanos() as i32; 51 spec.it_value.tv_nsec = libc::c_long::from(nsec); 52 53 if let Some(int) = interval { 54 spec.it_interval.tv_sec = int.as_secs() as libc::time_t; 55 // nsec always fits in i32 because subsec_nanos is defined to be less than one billion. 56 let nsec = int.subsec_nanos() as i32; 57 spec.it_interval.tv_nsec = libc::c_long::from(nsec); 58 } 59 60 // Safe because this doesn't modify any memory and we check the return value. 61 let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) }; 62 if ret < 0 { 63 return errno_result(); 64 } 65 66 Ok(()) 67 } 68 69 /// Waits until the timer expires. The return value represents the number of times the timer 70 /// has expired since the last time `wait` was called. If the timer has not yet expired once 71 /// this call will block until it does. wait(&self) -> Result<u64>72 pub fn wait(&self) -> Result<u64> { 73 let mut count = 0u64; 74 75 // Safe because this will only modify |buf| and we check the return value. 76 let ret = unsafe { 77 libc::read( 78 self.as_raw_fd(), 79 &mut count as *mut _ as *mut libc::c_void, 80 mem::size_of_val(&count), 81 ) 82 }; 83 if ret < 0 { 84 return errno_result(); 85 } 86 87 // The bytes in the buffer are guaranteed to be in native byte-order so we don't need to 88 // use from_le or from_be. 89 Ok(count) 90 } 91 92 /// Disarms the timer. clear(&self) -> Result<()>93 pub fn clear(&self) -> Result<()> { 94 // Safe because we are zero-initializing a struct with only primitive member fields. 95 let spec: libc::itimerspec = unsafe { mem::zeroed() }; 96 97 // Safe because this doesn't modify any memory and we check the return value. 98 let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) }; 99 if ret < 0 { 100 return errno_result(); 101 } 102 103 Ok(()) 104 } 105 106 /// Returns the resolution of timers on the host. resolution() -> Result<Duration>107 pub fn resolution() -> Result<Duration> { 108 // Safe because we are zero-initializing a struct with only primitive member fields. 109 let mut res: libc::timespec = unsafe { mem::zeroed() }; 110 111 // Safe because it only modifies a local struct and we check the return value. 112 let ret = unsafe { clock_getres(CLOCK_MONOTONIC, &mut res) }; 113 114 if ret != 0 { 115 return errno_result(); 116 } 117 118 Ok(Duration::new(res.tv_sec as u64, res.tv_nsec as u32)) 119 } 120 } 121 122 impl AsRawFd for TimerFd { as_raw_fd(&self) -> RawFd123 fn as_raw_fd(&self) -> RawFd { 124 self.0.as_raw_fd() 125 } 126 } 127 128 impl FromRawFd for TimerFd { from_raw_fd(fd: RawFd) -> Self129 unsafe fn from_raw_fd(fd: RawFd) -> Self { 130 TimerFd(File::from_raw_fd(fd)) 131 } 132 } 133 134 impl IntoRawFd for TimerFd { into_raw_fd(self) -> RawFd135 fn into_raw_fd(self) -> RawFd { 136 self.0.into_raw_fd() 137 } 138 } 139 140 /// FakeTimerFd: For use in tests. 141 pub struct FakeTimerFd { 142 clock: Arc<Mutex<FakeClock>>, 143 deadline_ns: Option<u64>, 144 interval: Option<Duration>, 145 fd: EventFd, 146 } 147 148 impl FakeTimerFd { 149 /// Creates a new fake timerfd. The timer is initally disarmed and must be armed by calling 150 /// `reset`. new(clock: Arc<Mutex<FakeClock>>) -> Self151 pub fn new(clock: Arc<Mutex<FakeClock>>) -> Self { 152 FakeTimerFd { 153 clock, 154 deadline_ns: None, 155 interval: None, 156 fd: EventFd::new().unwrap(), 157 } 158 } 159 duration_to_nanos(d: Duration) -> u64160 fn duration_to_nanos(d: Duration) -> u64 { 161 d.as_secs() * 1_000_000_000 + u64::from(d.subsec_nanos()) 162 } 163 164 /// Sets the timer to expire after `dur`. If `interval` is not `None` it represents 165 /// the period for repeated expirations after the initial expiration. Otherwise 166 /// the timer will expire just once. Cancels any existing duration and repeating interval. reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()>167 pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> { 168 let mut guard = self.clock.lock(); 169 let deadline = guard.nanos() + FakeTimerFd::duration_to_nanos(dur); 170 self.deadline_ns = Some(deadline); 171 self.interval = interval; 172 guard.add_event_fd(deadline, self.fd.try_clone()?); 173 Ok(()) 174 } 175 176 /// Waits until the timer expires. The return value represents the number of times the timer 177 /// has expired since the last time `wait` was called. If the timer has not yet expired once 178 /// this call will block until it does. wait(&mut self) -> Result<u64>179 pub fn wait(&mut self) -> Result<u64> { 180 loop { 181 self.fd.read()?; 182 if let Some(deadline_ns) = &mut self.deadline_ns { 183 let mut guard = self.clock.lock(); 184 let now = guard.nanos(); 185 if now >= *deadline_ns { 186 let mut expirys = 0; 187 if let Some(interval) = self.interval { 188 let interval_ns = FakeTimerFd::duration_to_nanos(interval); 189 if interval_ns > 0 { 190 expirys += (now - *deadline_ns) / interval_ns; 191 *deadline_ns += (expirys + 1) * interval_ns; 192 guard.add_event_fd(*deadline_ns, self.fd.try_clone()?); 193 } 194 } 195 return Ok(expirys + 1); 196 } 197 } 198 } 199 } 200 201 /// Disarms the timer. clear(&mut self) -> Result<()>202 pub fn clear(&mut self) -> Result<()> { 203 self.deadline_ns = None; 204 self.interval = None; 205 Ok(()) 206 } 207 208 /// Returns the resolution of timers on the host. resolution() -> Result<Duration>209 pub fn resolution() -> Result<Duration> { 210 Ok(Duration::from_nanos(1)) 211 } 212 } 213 214 impl AsRawFd for FakeTimerFd { as_raw_fd(&self) -> RawFd215 fn as_raw_fd(&self) -> RawFd { 216 self.fd.as_raw_fd() 217 } 218 } 219 220 impl IntoRawFd for FakeTimerFd { into_raw_fd(self) -> RawFd221 fn into_raw_fd(self) -> RawFd { 222 self.fd.into_raw_fd() 223 } 224 } 225 226 #[cfg(test)] 227 mod tests { 228 use super::*; 229 use std::{ 230 thread::sleep, 231 time::{Duration, Instant}, 232 }; 233 234 #[test] one_shot()235 fn one_shot() { 236 let tfd = TimerFd::new().expect("failed to create timerfd"); 237 238 let dur = Duration::from_millis(200); 239 let now = Instant::now(); 240 tfd.reset(dur, None).expect("failed to arm timer"); 241 242 let count = tfd.wait().expect("unable to wait for timer"); 243 244 assert_eq!(count, 1); 245 assert!(now.elapsed() >= dur); 246 } 247 248 #[test] repeating()249 fn repeating() { 250 let tfd = TimerFd::new().expect("failed to create timerfd"); 251 252 let dur = Duration::from_millis(200); 253 let interval = Duration::from_millis(100); 254 tfd.reset(dur, Some(interval)).expect("failed to arm timer"); 255 256 sleep(dur * 3); 257 258 let count = tfd.wait().expect("unable to wait for timer"); 259 assert!(count >= 5, "count = {}", count); 260 } 261 262 #[test] fake_one_shot()263 fn fake_one_shot() { 264 let clock = Arc::new(Mutex::new(FakeClock::new())); 265 let mut tfd = FakeTimerFd::new(clock.clone()); 266 267 let dur = Duration::from_nanos(200); 268 tfd.reset(dur, None).expect("failed to arm timer"); 269 270 clock.lock().add_ns(200); 271 272 let count = tfd.wait().expect("unable to wait for timer"); 273 274 assert_eq!(count, 1); 275 } 276 277 #[test] fake_repeating()278 fn fake_repeating() { 279 let clock = Arc::new(Mutex::new(FakeClock::new())); 280 let mut tfd = FakeTimerFd::new(clock.clone()); 281 282 let dur = Duration::from_nanos(200); 283 let interval = Duration::from_nanos(100); 284 tfd.reset(dur, Some(interval)).expect("failed to arm timer"); 285 286 clock.lock().add_ns(300); 287 288 let mut count = tfd.wait().expect("unable to wait for timer"); 289 // An expiration from the initial expiry and from 1 repeat. 290 assert_eq!(count, 2); 291 292 clock.lock().add_ns(300); 293 count = tfd.wait().expect("unable to wait for timer"); 294 assert_eq!(count, 3); 295 } 296 } 297