• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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