base/sys/linux/
event.rs

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
5use std::mem;
6use std::ptr;
7use std::time::Duration;
8
9use libc::c_void;
10use libc::eventfd;
11use libc::read;
12use libc::write;
13use libc::POLLIN;
14use serde::Deserialize;
15use serde::Serialize;
16
17use super::errno_result;
18use super::Error;
19use super::RawDescriptor;
20use super::Result;
21use crate::descriptor::AsRawDescriptor;
22use crate::descriptor::FromRawDescriptor;
23use crate::descriptor::IntoRawDescriptor;
24use crate::descriptor::SafeDescriptor;
25use crate::handle_eintr_errno;
26use crate::unix::duration_to_timespec;
27use 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)]
35pub(crate) struct PlatformEvent {
36    event_handle: SafeDescriptor,
37}
38
39/// Linux specific extensions to `Event`.
40pub 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
47impl 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
57impl 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
178impl AsRawDescriptor for PlatformEvent {
179    fn as_raw_descriptor(&self) -> RawDescriptor {
180        self.event_handle.as_raw_descriptor()
181    }
182}
183
184impl 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
192impl IntoRawDescriptor for PlatformEvent {
193    fn into_raw_descriptor(self) -> RawDescriptor {
194        self.event_handle.into_raw_descriptor()
195    }
196}
197
198impl From<PlatformEvent> for SafeDescriptor {
199    fn from(evt: PlatformEvent) -> Self {
200        evt.event_handle
201    }
202}
203
204impl From<SafeDescriptor> for PlatformEvent {
205    fn from(sd: SafeDescriptor) -> Self {
206        PlatformEvent { event_handle: sd }
207    }
208}
209
210#[cfg(test)]
211mod 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}