// Copyright 2018 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. use std::fs::File; use std::mem; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use std::ptr; use std::sync::Arc; use std::time::Duration; use sync::Mutex; use libc::{self, timerfd_create, timerfd_gettime, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC}; use crate::{errno_result, EventFd, FakeClock, Result}; /// A safe wrapper around a Linux timerfd (man 2 timerfd_create). pub struct TimerFd(File); impl TimerFd { /// Creates a new timerfd. The timer is initally disarmed and must be armed by calling /// `reset`. pub fn new() -> Result { // Safe because this doesn't modify any memory and we check the return value. let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC) }; if ret < 0 { return errno_result(); } // Safe because we uniquely own the file descriptor. Ok(TimerFd(unsafe { File::from_raw_fd(ret) })) } /// Sets the timer to expire after `dur`. If `interval` is not `None` it represents /// the period for repeated expirations after the initial expiration. Otherwise /// the timer will expire just once. Cancels any existing duration and repeating interval. pub fn reset(&mut self, dur: Duration, interval: Option) -> Result<()> { // Safe because we are zero-initializing a struct with only primitive member fields. let mut spec: libc::itimerspec = unsafe { mem::zeroed() }; spec.it_value.tv_sec = dur.as_secs() as libc::time_t; // nsec always fits in i32 because subsec_nanos is defined to be less than one billion. let nsec = dur.subsec_nanos() as i32; spec.it_value.tv_nsec = libc::c_long::from(nsec); if let Some(int) = interval { spec.it_interval.tv_sec = int.as_secs() as libc::time_t; // nsec always fits in i32 because subsec_nanos is defined to be less than one billion. let nsec = int.subsec_nanos() as i32; spec.it_interval.tv_nsec = libc::c_long::from(nsec); } // Safe because this doesn't modify any memory and we check the return value. let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) }; if ret < 0 { return errno_result(); } Ok(()) } /// Waits until the timer expires. The return value represents the number of times the timer /// has expired since the last time `wait` was called. If the timer has not yet expired once /// this call will block until it does. pub fn wait(&mut self) -> Result { let mut count = 0u64; // Safe because this will only modify |buf| and we check the return value. let ret = unsafe { libc::read( self.as_raw_fd(), &mut count as *mut _ as *mut libc::c_void, mem::size_of_val(&count), ) }; if ret < 0 { return errno_result(); } // The bytes in the buffer are guaranteed to be in native byte-order so we don't need to // use from_le or from_be. Ok(count) } /// Returns `true` if the timer is currently armed. pub fn is_armed(&self) -> Result { // Safe because we are zero-initializing a struct with only primitive member fields. let mut spec: libc::itimerspec = unsafe { mem::zeroed() }; // Safe because timerfd_gettime is trusted to only modify `spec`. let ret = unsafe { timerfd_gettime(self.as_raw_fd(), &mut spec) }; if ret < 0 { return errno_result(); } Ok(spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0) } /// Disarms the timer. pub fn clear(&mut self) -> Result<()> { // Safe because we are zero-initializing a struct with only primitive member fields. let spec: libc::itimerspec = unsafe { mem::zeroed() }; // Safe because this doesn't modify any memory and we check the return value. let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) }; if ret < 0 { return errno_result(); } Ok(()) } } impl AsRawFd for TimerFd { fn as_raw_fd(&self) -> RawFd { self.0.as_raw_fd() } } impl FromRawFd for TimerFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { TimerFd(File::from_raw_fd(fd)) } } impl IntoRawFd for TimerFd { fn into_raw_fd(self) -> RawFd { self.0.into_raw_fd() } } /// FakeTimerFd: For use in tests. pub struct FakeTimerFd { clock: Arc>, deadline_ns: Option, interval: Option, fd: EventFd, } impl FakeTimerFd { /// Creates a new fake timerfd. The timer is initally disarmed and must be armed by calling /// `reset`. pub fn new(clock: Arc>) -> Self { FakeTimerFd { clock, deadline_ns: None, interval: None, fd: EventFd::new().unwrap(), } } fn duration_to_nanos(d: Duration) -> u64 { d.as_secs() * 1_000_000_000 + u64::from(d.subsec_nanos()) } /// Sets the timer to expire after `dur`. If `interval` is not `None` it represents /// the period for repeated expirations after the initial expiration. Otherwise /// the timer will expire just once. Cancels any existing duration and repeating interval. pub fn reset(&mut self, dur: Duration, interval: Option) -> Result<()> { let mut guard = self.clock.lock(); let deadline = guard.nanos() + FakeTimerFd::duration_to_nanos(dur); self.deadline_ns = Some(deadline); self.interval = interval; guard.add_event_fd(deadline, self.fd.try_clone()?); Ok(()) } /// Waits until the timer expires. The return value represents the number of times the timer /// has expired since the last time `wait` was called. If the timer has not yet expired once /// this call will block until it does. pub fn wait(&mut self) -> Result { loop { self.fd.read()?; if let Some(deadline_ns) = &mut self.deadline_ns { let mut guard = self.clock.lock(); let now = guard.nanos(); if now >= *deadline_ns { let mut expirys = 0; if let Some(interval) = self.interval { let interval_ns = FakeTimerFd::duration_to_nanos(interval); if interval_ns > 0 { expirys += (now - *deadline_ns) / interval_ns; *deadline_ns += (expirys + 1) * interval_ns; guard.add_event_fd(*deadline_ns, self.fd.try_clone()?); } } return Ok(expirys + 1); } } } } /// Returns `true` if the timer is currently armed. pub fn is_armed(&self) -> Result { Ok(self.deadline_ns.is_some()) } /// Disarms the timer. pub fn clear(&mut self) -> Result<()> { self.deadline_ns = None; self.interval = None; Ok(()) } } impl AsRawFd for FakeTimerFd { fn as_raw_fd(&self) -> RawFd { self.fd.as_raw_fd() } } impl IntoRawFd for FakeTimerFd { fn into_raw_fd(self) -> RawFd { self.fd.into_raw_fd() } } #[cfg(test)] mod tests { use super::*; use std::thread::sleep; use std::time::{Duration, Instant}; #[test] fn one_shot() { let mut tfd = TimerFd::new().expect("failed to create timerfd"); assert_eq!(tfd.is_armed().unwrap(), false); let dur = Duration::from_millis(200); let now = Instant::now(); tfd.reset(dur.clone(), None).expect("failed to arm timer"); assert_eq!(tfd.is_armed().unwrap(), true); let count = tfd.wait().expect("unable to wait for timer"); assert_eq!(count, 1); assert!(now.elapsed() >= dur); } #[test] fn repeating() { let mut tfd = TimerFd::new().expect("failed to create timerfd"); let dur = Duration::from_millis(200); let interval = Duration::from_millis(100); tfd.reset(dur.clone(), Some(interval)) .expect("failed to arm timer"); sleep(dur * 3); let count = tfd.wait().expect("unable to wait for timer"); assert!(count >= 5, "count = {}", count); } #[test] fn fake_one_shot() { let clock = Arc::new(Mutex::new(FakeClock::new())); let mut tfd = FakeTimerFd::new(clock.clone()); assert_eq!(tfd.is_armed().unwrap(), false); let dur = Duration::from_nanos(200); tfd.reset(dur.clone(), None).expect("failed to arm timer"); assert_eq!(tfd.is_armed().unwrap(), true); clock.lock().add_ns(200); let count = tfd.wait().expect("unable to wait for timer"); assert_eq!(count, 1); } #[test] fn fake_repeating() { let clock = Arc::new(Mutex::new(FakeClock::new())); let mut tfd = FakeTimerFd::new(clock.clone()); let dur = Duration::from_nanos(200); let interval = Duration::from_nanos(100); tfd.reset(dur.clone(), Some(interval)) .expect("failed to arm timer"); clock.lock().add_ns(300); let mut count = tfd.wait().expect("unable to wait for timer"); // An expiration from the initial expiry and from 1 repeat. assert_eq!(count, 2); clock.lock().add_ns(300); count = tfd.wait().expect("unable to wait for timer"); assert_eq!(count, 3); } }