1 // Copyright 2019 Intel Corporation. All Rights Reserved.
2 //
3 // Copyright 2018 The Chromium OS Authors. All rights reserved.
4 //
5 // SPDX-License-Identifier: BSD-3-Clause
6 
7 //! Structure and functions for working with
8 //! [`timerfd`](http://man7.org/linux/man-pages/man2/timerfd_create.2.html).
9 
10 use std::fs::File;
11 use std::mem;
12 use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
13 use std::ptr;
14 use std::time::Duration;
15 
16 use libc::{self, timerfd_create, timerfd_gettime, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC};
17 
18 use crate::errno::{errno_result, Result};
19 
20 /// A safe wrapper around a Linux
21 /// [`timerfd`](http://man7.org/linux/man-pages/man2/timerfd_create.2.html).
22 #[derive(Debug)]
23 pub struct TimerFd(File);
24 
25 impl TimerFd {
26     /// Create a new [`TimerFd`](struct.TimerFd.html).
27     ///
28     /// This creates a nonsettable monotonically increasing clock that does not
29     /// change after system startup. The timer is initally disarmed and must be
30     /// armed by calling [`reset`](fn.reset.html).
new() -> Result<TimerFd>31     pub fn new() -> Result<TimerFd> {
32         // SAFETY: Safe because this doesn't modify any memory and we check the return value.
33         let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC) };
34         if ret < 0 {
35             return errno_result();
36         }
37 
38         // SAFETY: Safe because we uniquely own the file descriptor.
39         Ok(TimerFd(unsafe { File::from_raw_fd(ret) }))
40     }
41 
42     /// Arm the [`TimerFd`](struct.TimerFd.html).
43     ///
44     /// Set the timer to expire after `dur`.
45     ///
46     /// # Arguments
47     ///
48     /// * `dur`: Specify the initial expiration of the timer.
49     /// * `interval`: Specify the period for repeated expirations, depending on the
50     /// value passed. If `interval` is not `None`, it represents the period after
51     /// the initial expiration. Otherwise the timer will expire just once. Cancels
52     /// any existing duration and repeating interval.
53     ///
54     /// # Examples
55     ///
56     /// ```
57     /// extern crate vmm_sys_util;
58     /// # use std::time::Duration;
59     /// use vmm_sys_util::timerfd::TimerFd;
60     ///
61     /// let mut timer = TimerFd::new().unwrap();
62     /// let dur = Duration::from_millis(100);
63     /// let interval = Duration::from_millis(100);
64     ///
65     /// timer.reset(dur, Some(interval)).unwrap();
66     /// ```
reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()>67     pub fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> {
68         // SAFETY: Safe because we are zero-initializing a struct with only primitive member fields.
69         let mut spec: libc::itimerspec = unsafe { mem::zeroed() };
70         // https://github.com/rust-lang/libc/issues/1848
71         #[cfg_attr(target_env = "musl", allow(deprecated))]
72         {
73             spec.it_value.tv_sec = dur.as_secs() as libc::time_t;
74         }
75         // nsec always fits in i32 because subsec_nanos is defined to be less than one billion.
76         let nsec = dur.subsec_nanos() as i32;
77         spec.it_value.tv_nsec = libc::c_long::from(nsec);
78 
79         if let Some(int) = interval {
80             // https://github.com/rust-lang/libc/issues/1848
81             #[cfg_attr(target_env = "musl", allow(deprecated))]
82             {
83                 spec.it_interval.tv_sec = int.as_secs() as libc::time_t;
84             }
85             // nsec always fits in i32 because subsec_nanos is defined to be less than one billion.
86             let nsec = int.subsec_nanos() as i32;
87             spec.it_interval.tv_nsec = libc::c_long::from(nsec);
88         }
89 
90         // SAFETY: Safe because this doesn't modify any memory and we check the return value.
91         let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) };
92         if ret < 0 {
93             return errno_result();
94         }
95 
96         Ok(())
97     }
98 
99     /// Wait until the timer expires.
100     ///
101     /// The return value represents the number of times the timer has expired since
102     /// the last time `wait` was called. If the timer has not yet expired once,
103     /// this call will block until it does.
104     ///
105     /// # Examples
106     ///
107     /// ```
108     /// extern crate vmm_sys_util;
109     /// # use std::time::Duration;
110     /// # use std::thread::sleep;
111     /// use vmm_sys_util::timerfd::TimerFd;
112     ///
113     /// let mut timer = TimerFd::new().unwrap();
114     /// let dur = Duration::from_millis(100);
115     /// let interval = Duration::from_millis(100);
116     /// timer.reset(dur, Some(interval)).unwrap();
117     ///
118     /// sleep(dur * 3);
119     /// let count = timer.wait().unwrap();
120     /// assert!(count >= 3);
121     /// ```
wait(&mut self) -> Result<u64>122     pub fn wait(&mut self) -> Result<u64> {
123         let mut count = 0u64;
124 
125         // SAFETY: Safe because this will only modify |buf| and we check the return value.
126         let ret = unsafe {
127             libc::read(
128                 self.as_raw_fd(),
129                 &mut count as *mut _ as *mut libc::c_void,
130                 mem::size_of_val(&count),
131             )
132         };
133         if ret < 0 {
134             return errno_result();
135         }
136 
137         // The bytes in the buffer are guaranteed to be in native byte-order so we don't need to
138         // use from_le or from_be.
139         Ok(count)
140     }
141 
142     /// Tell if the timer is armed.
143     ///
144     /// Returns `Ok(true)` if the timer is currently armed, otherwise the errno set by
145     /// [`timerfd_gettime`](http://man7.org/linux/man-pages/man2/timerfd_create.2.html).
146     ///
147     /// # Examples
148     ///
149     /// ```
150     /// extern crate vmm_sys_util;
151     /// # use std::time::Duration;
152     /// use vmm_sys_util::timerfd::TimerFd;
153     ///
154     /// let mut timer = TimerFd::new().unwrap();
155     /// let dur = Duration::from_millis(100);
156     ///
157     /// timer.reset(dur, None).unwrap();
158     /// assert!(timer.is_armed().unwrap());
159     /// ```
is_armed(&self) -> Result<bool>160     pub fn is_armed(&self) -> Result<bool> {
161         // SAFETY: Safe because we are zero-initializing a struct with only primitive member fields.
162         let mut spec: libc::itimerspec = unsafe { mem::zeroed() };
163 
164         // SAFETY: Safe because timerfd_gettime is trusted to only modify `spec`.
165         let ret = unsafe { timerfd_gettime(self.as_raw_fd(), &mut spec) };
166         if ret < 0 {
167             return errno_result();
168         }
169 
170         Ok(spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0)
171     }
172 
173     /// Disarm the timer.
174     ///
175     /// Set zero to disarm the timer, referring to
176     /// [`timerfd_settime`](http://man7.org/linux/man-pages/man2/timerfd_create.2.html).
177     ///
178     /// # Examples
179     ///
180     /// ```
181     /// extern crate vmm_sys_util;
182     /// # use std::time::Duration;
183     /// use vmm_sys_util::timerfd::TimerFd;
184     ///
185     /// let mut timer = TimerFd::new().unwrap();
186     /// let dur = Duration::from_millis(100);
187     ///
188     /// timer.reset(dur, None).unwrap();
189     /// timer.clear().unwrap();
190     /// ```
clear(&mut self) -> Result<()>191     pub fn clear(&mut self) -> Result<()> {
192         // SAFETY: Safe because we are zero-initializing a struct with only primitive member fields.
193         let spec: libc::itimerspec = unsafe { mem::zeroed() };
194 
195         // SAFETY: Safe because this doesn't modify any memory and we check the return value.
196         let ret = unsafe { timerfd_settime(self.as_raw_fd(), 0, &spec, ptr::null_mut()) };
197         if ret < 0 {
198             return errno_result();
199         }
200 
201         Ok(())
202     }
203 }
204 
205 impl AsRawFd for TimerFd {
as_raw_fd(&self) -> RawFd206     fn as_raw_fd(&self) -> RawFd {
207         self.0.as_raw_fd()
208     }
209 }
210 
211 impl FromRawFd for TimerFd {
212     /// This function is unsafe as the primitives currently returned
213     /// have the contract that they are the sole owner of the file
214     /// descriptor they are wrapping. Usage of this function could
215     /// accidentally allow violating this contract which can cause memory
216     /// unsafety in code that relies on it being true.
from_raw_fd(fd: RawFd) -> Self217     unsafe fn from_raw_fd(fd: RawFd) -> Self {
218         TimerFd(File::from_raw_fd(fd))
219     }
220 }
221 
222 impl IntoRawFd for TimerFd {
into_raw_fd(self) -> RawFd223     fn into_raw_fd(self) -> RawFd {
224         self.0.into_raw_fd()
225     }
226 }
227 
228 #[cfg(test)]
229 mod tests {
230     #![allow(clippy::undocumented_unsafe_blocks)]
231     use super::*;
232     use std::thread::sleep;
233     use std::time::{Duration, Instant};
234 
235     #[test]
test_from_raw_fd()236     fn test_from_raw_fd() {
237         let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC) };
238         let tfd = unsafe { TimerFd::from_raw_fd(ret) };
239         assert!(!tfd.is_armed().unwrap());
240     }
241 
242     #[test]
test_into_raw_fd()243     fn test_into_raw_fd() {
244         let tfd = TimerFd::new().expect("failed to create timerfd");
245         let fd = tfd.into_raw_fd();
246         assert!(fd > 0);
247     }
248     #[test]
test_one_shot()249     fn test_one_shot() {
250         let mut tfd = TimerFd::new().expect("failed to create timerfd");
251         assert!(!tfd.is_armed().unwrap());
252 
253         let dur = Duration::from_millis(200);
254         let now = Instant::now();
255         tfd.reset(dur, None).expect("failed to arm timer");
256 
257         assert!(tfd.is_armed().unwrap());
258 
259         let count = tfd.wait().expect("unable to wait for timer");
260 
261         assert_eq!(count, 1);
262         assert!(now.elapsed() >= dur);
263         tfd.clear().expect("unable to clear the timer");
264         assert!(!tfd.is_armed().unwrap());
265     }
266 
267     #[test]
test_repeating()268     fn test_repeating() {
269         let mut tfd = TimerFd::new().expect("failed to create timerfd");
270 
271         let dur = Duration::from_millis(200);
272         let interval = Duration::from_millis(100);
273         tfd.reset(dur, Some(interval)).expect("failed to arm timer");
274 
275         sleep(dur * 3);
276 
277         let count = tfd.wait().expect("unable to wait for timer");
278         assert!(count >= 5, "count = {}", count);
279         tfd.clear().expect("unable to clear the timer");
280         assert!(!tfd.is_armed().unwrap());
281     }
282 }
283