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