• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
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::{
6     mem,
7     ops::Deref,
8     os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd},
9     ptr,
10     time::Duration,
11 };
12 
13 use libc::{c_void, eventfd, read, write, POLLIN};
14 use serde::{Deserialize, Serialize};
15 
16 use super::{
17     duration_to_timespec, errno_result, generate_scoped_event, AsRawDescriptor, FromRawDescriptor,
18     IntoRawDescriptor, RawDescriptor, Result, SafeDescriptor,
19 };
20 
21 /// A safe wrapper around a Linux eventfd (man 2 eventfd).
22 ///
23 /// An eventfd is useful because it is sendable across processes and can be used for signaling in
24 /// and out of the KVM API. They can also be polled like any other file descriptor.
25 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
26 #[serde(transparent)]
27 pub struct EventFd {
28     event_handle: SafeDescriptor,
29 }
30 
31 /// Wrapper around the return value of doing a read on an EventFd which distinguishes between
32 /// getting a valid count of the number of times the eventfd has been written to and timing out
33 /// waiting for the count to be non-zero.
34 #[derive(Debug, PartialEq, Eq)]
35 pub enum EventReadResult {
36     Count(u64),
37     Timeout,
38 }
39 
40 impl EventFd {
41     /// Creates a new blocking EventFd with an initial value of 0.
new() -> Result<EventFd>42     pub fn new() -> Result<EventFd> {
43         // This is safe because eventfd merely allocated an eventfd for our process and we handle
44         // the error case.
45         let ret = unsafe { eventfd(0, 0) };
46         if ret < 0 {
47             return errno_result();
48         }
49         // This is safe because we checked ret for success and know the kernel gave us an fd that we
50         // own.
51         Ok(EventFd {
52             event_handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) },
53         })
54     }
55 
56     /// Adds `v` to the eventfd's count, blocking until this won't overflow the count.
write(&self, v: u64) -> Result<()>57     pub fn write(&self, v: u64) -> Result<()> {
58         // This is safe because we made this fd and the pointer we pass can not overflow because we
59         // give the syscall's size parameter properly.
60         let ret = unsafe {
61             write(
62                 self.as_raw_fd(),
63                 &v as *const u64 as *const c_void,
64                 mem::size_of::<u64>(),
65             )
66         };
67         if ret <= 0 {
68             return errno_result();
69         }
70         Ok(())
71     }
72 
73     /// Blocks until the the eventfd's count is non-zero, then resets the count to zero.
read(&self) -> Result<u64>74     pub fn read(&self) -> Result<u64> {
75         let mut buf: u64 = 0;
76         let ret = unsafe {
77             // This is safe because we made this fd and the pointer we pass can not overflow because
78             // we give the syscall's size parameter properly.
79             read(
80                 self.as_raw_fd(),
81                 &mut buf as *mut u64 as *mut c_void,
82                 mem::size_of::<u64>(),
83             )
84         };
85         if ret <= 0 {
86             return errno_result();
87         }
88         Ok(buf)
89     }
90 
91     /// Blocks for a maximum of `timeout` duration until the the eventfd's count is non-zero. If
92     /// a timeout does not occur then the count is returned as a EventReadResult::Count(count),
93     /// and the count is reset to 0. If a timeout does occur then this function will return
94     /// EventReadResult::Timeout.
read_timeout(&self, timeout: Duration) -> Result<EventReadResult>95     pub fn read_timeout(&self, timeout: Duration) -> Result<EventReadResult> {
96         let mut pfd = libc::pollfd {
97             fd: self.as_raw_descriptor(),
98             events: POLLIN,
99             revents: 0,
100         };
101         let timeoutspec: libc::timespec = duration_to_timespec(timeout);
102         // Safe because this only modifies |pfd| and we check the return value
103         let ret = unsafe {
104             libc::ppoll(
105                 &mut pfd as *mut libc::pollfd,
106                 1,
107                 &timeoutspec,
108                 ptr::null_mut(),
109             )
110         };
111         if ret < 0 {
112             return errno_result();
113         }
114 
115         // no return events (revents) means we got a timeout
116         if pfd.revents == 0 {
117             return Ok(EventReadResult::Timeout);
118         }
119 
120         let mut buf = 0u64;
121         // This is safe because we made this fd and the pointer we pass can not overflow because
122         // we give the syscall's size parameter properly.
123         let ret = unsafe {
124             libc::read(
125                 self.as_raw_descriptor(),
126                 &mut buf as *mut _ as *mut c_void,
127                 mem::size_of::<u64>(),
128             )
129         };
130         if ret < 0 {
131             return errno_result();
132         }
133         Ok(EventReadResult::Count(buf))
134     }
135 
136     /// Clones this EventFd, internally creating a new file descriptor. The new EventFd will share
137     /// the same underlying count within the kernel.
try_clone(&self) -> Result<EventFd>138     pub fn try_clone(&self) -> Result<EventFd> {
139         self.event_handle
140             .try_clone()
141             .map(|event_handle| EventFd { event_handle })
142     }
143 }
144 
145 impl AsRawFd for EventFd {
as_raw_fd(&self) -> RawFd146     fn as_raw_fd(&self) -> RawFd {
147         self.event_handle.as_raw_fd()
148     }
149 }
150 
151 impl AsRawDescriptor for EventFd {
as_raw_descriptor(&self) -> RawDescriptor152     fn as_raw_descriptor(&self) -> RawDescriptor {
153         self.event_handle.as_raw_descriptor()
154     }
155 }
156 
157 impl FromRawFd for EventFd {
from_raw_fd(fd: RawFd) -> Self158     unsafe fn from_raw_fd(fd: RawFd) -> Self {
159         EventFd {
160             event_handle: SafeDescriptor::from_raw_descriptor(fd),
161         }
162     }
163 }
164 
165 impl IntoRawFd for EventFd {
into_raw_fd(self) -> RawFd166     fn into_raw_fd(self) -> RawFd {
167         self.event_handle.into_raw_descriptor()
168     }
169 }
170 
171 impl From<EventFd> for SafeDescriptor {
from(evt: EventFd) -> Self172     fn from(evt: EventFd) -> Self {
173         evt.event_handle
174     }
175 }
176 
177 generate_scoped_event!(EventFd);
178 
179 #[cfg(test)]
180 mod tests {
181     use super::*;
182 
183     #[test]
new()184     fn new() {
185         EventFd::new().unwrap();
186     }
187 
188     #[test]
read_write()189     fn read_write() {
190         let evt = EventFd::new().unwrap();
191         evt.write(55).unwrap();
192         assert_eq!(evt.read(), Ok(55));
193     }
194 
195     #[test]
clone()196     fn clone() {
197         let evt = EventFd::new().unwrap();
198         let evt_clone = evt.try_clone().unwrap();
199         evt.write(923).unwrap();
200         assert_eq!(evt_clone.read(), Ok(923));
201     }
202 
203     #[test]
scoped_event()204     fn scoped_event() {
205         let scoped_evt = ScopedEvent::new().unwrap();
206         let evt_clone: EventFd = scoped_evt.try_clone().unwrap();
207         drop(scoped_evt);
208         assert_eq!(evt_clone.read(), Ok(1));
209     }
210 
211     #[test]
eventfd_from_scoped_event()212     fn eventfd_from_scoped_event() {
213         let scoped_evt = ScopedEvent::new().unwrap();
214         let evt: EventFd = scoped_evt.into();
215         evt.write(1).unwrap();
216     }
217 
218     #[test]
timeout()219     fn timeout() {
220         let evt = EventFd::new().expect("failed to create eventfd");
221         assert_eq!(
222             evt.read_timeout(Duration::from_millis(1))
223                 .expect("failed to read from eventfd with timeout"),
224             EventReadResult::Timeout
225         );
226     }
227 }
228