xref: /aosp_15_r20/external/crosvm/base/src/sys/linux/timer.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2018 The ChromiumOS Authors
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::mem;
6 use std::os::unix::io::AsRawFd;
7 use std::os::unix::io::RawFd;
8 use std::ptr;
9 use std::time::Duration;
10 
11 use libc::clock_getres;
12 use libc::timerfd_create;
13 use libc::timerfd_settime;
14 use libc::CLOCK_MONOTONIC;
15 use libc::EAGAIN;
16 use libc::POLLIN;
17 use libc::TFD_CLOEXEC;
18 use libc::TFD_NONBLOCK;
19 
20 use super::super::errno_result;
21 use super::super::Error;
22 use super::super::Result;
23 use crate::descriptor::AsRawDescriptor;
24 use crate::descriptor::FromRawDescriptor;
25 use crate::descriptor::SafeDescriptor;
26 use crate::handle_eintr_errno;
27 use crate::timer::Timer;
28 use crate::timer::TimerTrait;
29 use crate::unix::duration_to_timespec;
30 
31 impl AsRawFd for Timer {
as_raw_fd(&self) -> RawFd32     fn as_raw_fd(&self) -> RawFd {
33         self.handle.as_raw_descriptor()
34     }
35 }
36 
37 impl Timer {
38     /// Creates a new timerfd.  The timer is initally disarmed and must be armed by calling
39     /// `reset`.
new() -> Result<Timer>40     pub fn new() -> Result<Timer> {
41         // SAFETY:
42         // Safe because this doesn't modify any memory and we check the return value.
43         let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK) };
44         if ret < 0 {
45             return errno_result();
46         }
47 
48         Ok(Timer {
49             // SAFETY:
50             // Safe because we uniquely own the file descriptor.
51             handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) },
52             interval: None,
53         })
54     }
55 
56     // Calls `timerfd_settime()` and stores the new value of `interval`.
set_time(&mut self, dur: Option<Duration>, interval: Option<Duration>) -> Result<()>57     fn set_time(&mut self, dur: Option<Duration>, interval: Option<Duration>) -> Result<()> {
58         // The posix implementation of timer does not need self.interval, but we
59         // save it anyways to keep a consistent interface.
60         self.interval = interval;
61 
62         let spec = libc::itimerspec {
63             it_interval: duration_to_timespec(interval.unwrap_or_default()),
64             it_value: duration_to_timespec(dur.unwrap_or_default()),
65         };
66 
67         // SAFETY:
68         // Safe because this doesn't modify any memory and we check the return value.
69         let ret = unsafe { timerfd_settime(self.as_raw_descriptor(), 0, &spec, ptr::null_mut()) };
70         if ret < 0 {
71             return errno_result();
72         }
73 
74         Ok(())
75     }
76 }
77 
78 impl TimerTrait for Timer {
reset_oneshot(&mut self, dur: Duration) -> Result<()>79     fn reset_oneshot(&mut self, dur: Duration) -> Result<()> {
80         self.set_time(Some(dur), None)
81     }
82 
reset_repeating(&mut self, dur: Duration) -> Result<()>83     fn reset_repeating(&mut self, dur: Duration) -> Result<()> {
84         self.set_time(Some(dur), Some(dur))
85     }
86 
clear(&mut self) -> Result<()>87     fn clear(&mut self) -> Result<()> {
88         self.set_time(None, None)
89     }
90 
wait(&mut self) -> Result<()>91     fn wait(&mut self) -> Result<()> {
92         let mut pfd = libc::pollfd {
93             fd: self.as_raw_descriptor(),
94             events: POLLIN,
95             revents: 0,
96         };
97 
98         // SAFETY:
99         // Safe because this only modifies |pfd| and we check the return value
100         let ret = handle_eintr_errno!(unsafe {
101             libc::ppoll(
102                 &mut pfd as *mut libc::pollfd,
103                 1,
104                 ptr::null_mut(),
105                 ptr::null_mut(),
106             )
107         });
108 
109         if ret < 0 {
110             return errno_result();
111         }
112 
113         // EAGAIN is a valid error in the case where another thread has called timerfd_settime
114         // in between this thread calling ppoll and read. Since the ppoll returned originally
115         // without any revents it means the timer did expire, so we treat this as a
116         // WaitResult::Expired.
117         let _ = self.mark_waited()?;
118 
119         Ok(())
120     }
121 
mark_waited(&mut self) -> Result<bool>122     fn mark_waited(&mut self) -> Result<bool> {
123         let mut count = 0u64;
124 
125         // The timerfd is in non-blocking mode, so this should return immediately.
126         // SAFETY: We own the FD and provide a valid buffer we have exclusive access to.
127         let ret = unsafe {
128             libc::read(
129                 self.as_raw_descriptor(),
130                 &mut count as *mut _ as *mut libc::c_void,
131                 mem::size_of_val(&count),
132             )
133         };
134 
135         if ret < 0 {
136             if Error::last().errno() == EAGAIN {
137                 Ok(true)
138             } else {
139                 errno_result()
140             }
141         } else {
142             Ok(false)
143         }
144     }
145 
resolution(&self) -> Result<Duration>146     fn resolution(&self) -> Result<Duration> {
147         // SAFETY:
148         // Safe because we are zero-initializing a struct with only primitive member fields.
149         let mut res: libc::timespec = unsafe { mem::zeroed() };
150 
151         // SAFETY:
152         // Safe because it only modifies a local struct and we check the return value.
153         let ret = unsafe { clock_getres(CLOCK_MONOTONIC, &mut res) };
154 
155         if ret != 0 {
156             return errno_result();
157         }
158 
159         Ok(Duration::new(res.tv_sec as u64, res.tv_nsec as u32))
160     }
161 }
162