vmm_sys_util/linux/timerfd.rs
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
10use std::fs::File;
11use std::mem;
12use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
13use std::ptr;
14use std::time::Duration;
15
16use libc::{self, timerfd_create, timerfd_gettime, timerfd_settime, CLOCK_MONOTONIC, TFD_CLOEXEC};
17
18use 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)]
23pub struct TimerFd(File);
24
25impl 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).
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 /// ```
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 /// ```
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 /// ```
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 /// ```
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
205impl AsRawFd for TimerFd {
206 fn as_raw_fd(&self) -> RawFd {
207 self.0.as_raw_fd()
208 }
209}
210
211impl 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.
217 unsafe fn from_raw_fd(fd: RawFd) -> Self {
218 TimerFd(File::from_raw_fd(fd))
219 }
220}
221
222impl IntoRawFd for TimerFd {
223 fn into_raw_fd(self) -> RawFd {
224 self.0.into_raw_fd()
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 #![allow(clippy::undocumented_unsafe_blocks)]
231 use super::*;
232 use std::thread::sleep;
233 use std::time::{Duration, Instant};
234
235 #[test]
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]
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]
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]
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}