Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/linux/event.rs
5394 views
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.
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.
44
fn read_count(&self) -> Result<u64>;
45
}
46
47
impl EventExt for crate::Event {
48
fn write_count(&self, v: u64) -> Result<()> {
49
self.0.write_count(v)
50
}
51
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.
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`.
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`.
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`.
119
pub fn signal(&self) -> Result<()> {
120
self.write_count(1)
121
}
122
123
/// See `Event::wait`.
124
pub fn wait(&self) -> Result<()> {
125
self.read_count().map(|_| ())
126
}
127
128
/// See `Event::wait_timeout`.
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`.
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.
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 {
179
fn as_raw_descriptor(&self) -> RawDescriptor {
180
self.event_handle.as_raw_descriptor()
181
}
182
}
183
184
impl FromRawDescriptor for PlatformEvent {
185
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 {
193
fn into_raw_descriptor(self) -> RawDescriptor {
194
self.event_handle.into_raw_descriptor()
195
}
196
}
197
198
impl From<PlatformEvent> for SafeDescriptor {
199
fn from(evt: PlatformEvent) -> Self {
200
evt.event_handle
201
}
202
}
203
204
impl From<SafeDescriptor> for PlatformEvent {
205
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]
217
fn new() {
218
Event::new().unwrap();
219
}
220
221
#[test]
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]
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]
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
247