xref: /aosp_15_r20/external/crosvm/base/src/sys/linux/event.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2017 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::ptr;
7 use std::time::Duration;
8 
9 use libc::c_void;
10 use libc::eventfd;
11 use libc::read;
12 use libc::write;
13 use libc::POLLIN;
14 use serde::Deserialize;
15 use serde::Serialize;
16 
17 use super::errno_result;
18 use super::Error;
19 use super::RawDescriptor;
20 use super::Result;
21 use crate::descriptor::AsRawDescriptor;
22 use crate::descriptor::FromRawDescriptor;
23 use crate::descriptor::IntoRawDescriptor;
24 use crate::descriptor::SafeDescriptor;
25 use crate::handle_eintr_errno;
26 use crate::unix::duration_to_timespec;
27 use crate::EventWaitResult;
28 
29 /// A safe wrapper around a Linux eventfd (man 2 eventfd).
30 ///
31 /// An eventfd is useful because it is sendable across processes and can be used for signaling in
32 /// and out of the KVM API. They can also be polled like any other file descriptor.
33 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
34 #[serde(transparent)]
35 pub(crate) struct PlatformEvent {
36     event_handle: SafeDescriptor,
37 }
38 
39 /// Linux specific extensions to `Event`.
40 pub trait EventExt {
41     /// Adds `v` to the eventfd's count, blocking until this won't overflow the count.
write_count(&self, v: u64) -> Result<()>42     fn write_count(&self, v: u64) -> Result<()>;
43     /// Blocks until the the eventfd's count is non-zero, then resets the count to zero.
read_count(&self) -> Result<u64>44     fn read_count(&self) -> Result<u64>;
45 }
46 
47 impl EventExt for crate::Event {
write_count(&self, v: u64) -> Result<()>48     fn write_count(&self, v: u64) -> Result<()> {
49         self.0.write_count(v)
50     }
51 
read_count(&self) -> Result<u64>52     fn read_count(&self) -> Result<u64> {
53         self.0.read_count()
54     }
55 }
56 
57 impl PlatformEvent {
58     /// Creates a new blocking eventfd with an initial value of 0.
new() -> Result<PlatformEvent>59     pub fn new() -> Result<PlatformEvent> {
60         // SAFETY:
61         // This is safe because eventfd merely allocated an eventfd for our process and we handle
62         // the error case.
63         let ret = unsafe { eventfd(0, 0) };
64         if ret < 0 {
65             return errno_result();
66         }
67         Ok(PlatformEvent {
68             // SAFETY:
69             // This is safe because we checked ret for success and know the kernel gave us an fd
70             // that we own.
71             event_handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) },
72         })
73     }
74 
75     /// See `EventExt::write_count`.
write_count(&self, v: u64) -> Result<()>76     pub fn write_count(&self, v: u64) -> Result<()> {
77         // SAFETY:
78         // This is safe because we made this fd and the pointer we pass can not overflow because we
79         // give the syscall's size parameter properly.
80         let ret = handle_eintr_errno!(unsafe {
81             write(
82                 self.as_raw_descriptor(),
83                 &v as *const u64 as *const c_void,
84                 mem::size_of::<u64>(),
85             )
86         });
87         if ret < 0 {
88             return errno_result();
89         }
90         if ret as usize != mem::size_of::<u64>() {
91             return Err(Error::new(libc::EIO));
92         }
93         Ok(())
94     }
95 
96     /// See `EventExt::read_count`.
read_count(&self) -> Result<u64>97     pub fn read_count(&self) -> Result<u64> {
98         let mut buf: u64 = 0;
99         // SAFETY:
100         // This is safe because we made this fd and the pointer we pass can not overflow because
101         // we give the syscall's size parameter properly.
102         let ret = handle_eintr_errno!(unsafe {
103             read(
104                 self.as_raw_descriptor(),
105                 &mut buf as *mut u64 as *mut c_void,
106                 mem::size_of::<u64>(),
107             )
108         });
109         if ret < 0 {
110             return errno_result();
111         }
112         if ret as usize != mem::size_of::<u64>() {
113             return Err(Error::new(libc::EIO));
114         }
115         Ok(buf)
116     }
117 
118     /// See `Event::signal`.
signal(&self) -> Result<()>119     pub fn signal(&self) -> Result<()> {
120         self.write_count(1)
121     }
122 
123     /// See `Event::wait`.
wait(&self) -> Result<()>124     pub fn wait(&self) -> Result<()> {
125         self.read_count().map(|_| ())
126     }
127 
128     /// See `Event::wait_timeout`.
wait_timeout(&self, timeout: Duration) -> Result<EventWaitResult>129     pub fn wait_timeout(&self, timeout: Duration) -> Result<EventWaitResult> {
130         let mut pfd = libc::pollfd {
131             fd: self.as_raw_descriptor(),
132             events: POLLIN,
133             revents: 0,
134         };
135         let timeoutspec: libc::timespec = duration_to_timespec(timeout);
136         // SAFETY:
137         // Safe because this only modifies |pfd| and we check the return value
138         let ret = unsafe {
139             libc::ppoll(
140                 &mut pfd as *mut libc::pollfd,
141                 1,
142                 &timeoutspec,
143                 ptr::null_mut(),
144             )
145         };
146         if ret < 0 {
147             return errno_result();
148         }
149 
150         // no return events (revents) means we got a timeout
151         if pfd.revents == 0 {
152             return Ok(EventWaitResult::TimedOut);
153         }
154 
155         self.wait()?;
156         Ok(EventWaitResult::Signaled)
157     }
158 
159     /// See `Event::reset`.
reset(&self) -> Result<()>160     pub fn reset(&self) -> Result<()> {
161         // If the eventfd is currently signaled (counter > 0), `wait_timeout()` will `read()` it to
162         // reset the count. Otherwise (if the eventfd is not signaled), `wait_timeout()` will return
163         // immediately since we pass a zero duration. We don't care about the EventWaitResult; we
164         // just want a non-blocking read to reset the counter.
165         let _: EventWaitResult = self.wait_timeout(Duration::ZERO)?;
166         Ok(())
167     }
168 
169     /// Clones this eventfd, internally creating a new file descriptor. The new eventfd will share
170     /// the same underlying count within the kernel.
try_clone(&self) -> Result<PlatformEvent>171     pub fn try_clone(&self) -> Result<PlatformEvent> {
172         self.event_handle
173             .try_clone()
174             .map(|event_handle| PlatformEvent { event_handle })
175     }
176 }
177 
178 impl AsRawDescriptor for PlatformEvent {
as_raw_descriptor(&self) -> RawDescriptor179     fn as_raw_descriptor(&self) -> RawDescriptor {
180         self.event_handle.as_raw_descriptor()
181     }
182 }
183 
184 impl FromRawDescriptor for PlatformEvent {
from_raw_descriptor(descriptor: RawDescriptor) -> Self185     unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
186         PlatformEvent {
187             event_handle: SafeDescriptor::from_raw_descriptor(descriptor),
188         }
189     }
190 }
191 
192 impl IntoRawDescriptor for PlatformEvent {
into_raw_descriptor(self) -> RawDescriptor193     fn into_raw_descriptor(self) -> RawDescriptor {
194         self.event_handle.into_raw_descriptor()
195     }
196 }
197 
198 impl From<PlatformEvent> for SafeDescriptor {
from(evt: PlatformEvent) -> Self199     fn from(evt: PlatformEvent) -> Self {
200         evt.event_handle
201     }
202 }
203 
204 impl From<SafeDescriptor> for PlatformEvent {
from(sd: SafeDescriptor) -> Self205     fn from(sd: SafeDescriptor) -> Self {
206         PlatformEvent { event_handle: sd }
207     }
208 }
209 
210 #[cfg(test)]
211 mod tests {
212     use super::*;
213     use crate::Event;
214     use crate::EventExt;
215 
216     #[test]
new()217     fn new() {
218         Event::new().unwrap();
219     }
220 
221     #[test]
read_write()222     fn read_write() {
223         let evt = Event::new().unwrap();
224         evt.write_count(55).unwrap();
225         assert_eq!(evt.read_count(), Ok(55));
226     }
227 
228     #[test]
clone()229     fn clone() {
230         let evt = Event::new().unwrap();
231         let evt_clone = evt.try_clone().unwrap();
232         evt.write_count(923).unwrap();
233         assert_eq!(evt_clone.read_count(), Ok(923));
234     }
235 
236     #[test]
timeout()237     fn timeout() {
238         let evt = Event::new().expect("failed to create eventfd");
239         assert_eq!(
240             evt.wait_timeout(Duration::from_millis(1))
241                 .expect("failed to read from eventfd with timeout"),
242             EventWaitResult::TimedOut
243         );
244     }
245 }
246