• 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::{
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