vmm_sys_util/linux/eventfd.rs
1// Copyright 2019 Intel Corporation. All Rights Reserved.
2//
3// Copyright 2017 The Chromium OS Authors. All rights reserved.
4//
5// SPDX-License-Identifier: BSD-3-Clause
6
7//! Structure and wrapper functions for working with
8//! [`eventfd`](http://man7.org/linux/man-pages/man2/eventfd.2.html).
9
10use std::fs::File;
11use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
12use std::{io, mem, result};
13
14use libc::{c_void, dup, eventfd, read, write};
15
16// Reexport commonly used flags from libc.
17pub use libc::{EFD_CLOEXEC, EFD_NONBLOCK, EFD_SEMAPHORE};
18
19/// A safe wrapper around Linux
20/// [`eventfd`](http://man7.org/linux/man-pages/man2/eventfd.2.html).
21#[derive(Debug)]
22pub struct EventFd {
23 eventfd: File,
24}
25
26impl EventFd {
27 /// Create a new EventFd with an initial value.
28 ///
29 /// # Arguments
30 ///
31 /// * `flag`: The initial value used for creating the `EventFd`.
32 /// Refer to Linux [`eventfd`](http://man7.org/linux/man-pages/man2/eventfd.2.html).
33 /// # Examples
34 ///
35 /// ```
36 /// extern crate vmm_sys_util;
37 /// use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
38 ///
39 /// EventFd::new(EFD_NONBLOCK).unwrap();
40 /// ```
41 pub fn new(flag: i32) -> result::Result<EventFd, io::Error> {
42 // SAFETY: This is safe because eventfd merely allocated an eventfd for
43 // our process and we handle the error case.
44 let ret = unsafe { eventfd(0, flag) };
45 if ret < 0 {
46 Err(io::Error::last_os_error())
47 } else {
48 Ok(EventFd {
49 // SAFETY: This is safe because we checked ret for success and know
50 // the kernel gave us an fd that we own.
51 eventfd: unsafe { File::from_raw_fd(ret) },
52 })
53 }
54 }
55
56 /// Add a value to the eventfd's counter.
57 ///
58 /// When the addition causes the counter overflow, this would either block
59 /// until a [`read`](http://man7.org/linux/man-pages/man2/read.2.html) is
60 /// performed on the file descriptor, or fail with the
61 /// error EAGAIN if the file descriptor has been made nonblocking.
62 ///
63 /// # Arguments
64 ///
65 /// * `v`: the value to be added to the eventfd's counter.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// extern crate vmm_sys_util;
71 /// use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
72 ///
73 /// let evt = EventFd::new(EFD_NONBLOCK).unwrap();
74 /// evt.write(55).unwrap();
75 /// ```
76 pub fn write(&self, v: u64) -> result::Result<(), io::Error> {
77 // SAFETY: This is safe because we made this fd and the pointer we pass
78 // can not overflow because we give the syscall's size parameter properly.
79 let ret = unsafe {
80 write(
81 self.as_raw_fd(),
82 &v as *const u64 as *const c_void,
83 mem::size_of::<u64>(),
84 )
85 };
86 if ret <= 0 {
87 Err(io::Error::last_os_error())
88 } else {
89 Ok(())
90 }
91 }
92
93 /// Read a value from the eventfd.
94 ///
95 /// If the counter is zero, this would either block
96 /// until the counter becomes nonzero, or fail with the
97 /// error EAGAIN if the file descriptor has been made nonblocking.
98 ///
99 /// # Examples
100 ///
101 /// ```
102 /// extern crate vmm_sys_util;
103 /// use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
104 ///
105 /// let evt = EventFd::new(EFD_NONBLOCK).unwrap();
106 /// evt.write(55).unwrap();
107 /// assert_eq!(evt.read().unwrap(), 55);
108 /// ```
109 pub fn read(&self) -> result::Result<u64, io::Error> {
110 let mut buf: u64 = 0;
111 // SAFETY: This is safe because we made this fd and the pointer we
112 // pass can not overflow because we give the syscall's size parameter properly.
113 let ret = unsafe {
114 read(
115 self.as_raw_fd(),
116 &mut buf as *mut u64 as *mut c_void,
117 mem::size_of::<u64>(),
118 )
119 };
120 if ret < 0 {
121 Err(io::Error::last_os_error())
122 } else {
123 Ok(buf)
124 }
125 }
126
127 /// Clone this EventFd.
128 ///
129 /// This internally creates a new file descriptor and it will share the same
130 /// underlying count within the kernel.
131 ///
132 /// # Examples
133 ///
134 /// ```
135 /// extern crate vmm_sys_util;
136 /// use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
137 ///
138 /// let evt = EventFd::new(EFD_NONBLOCK).unwrap();
139 /// let evt_clone = evt.try_clone().unwrap();
140 /// evt.write(923).unwrap();
141 /// assert_eq!(evt_clone.read().unwrap(), 923);
142 /// ```
143 pub fn try_clone(&self) -> result::Result<EventFd, io::Error> {
144 // SAFETY: This is safe because we made this fd and properly check that it returns
145 // without error.
146 let ret = unsafe { dup(self.as_raw_fd()) };
147 if ret < 0 {
148 Err(io::Error::last_os_error())
149 } else {
150 Ok(EventFd {
151 // SAFETY: This is safe because we checked ret for success and know the kernel
152 // gave us an fd that we own.
153 eventfd: unsafe { File::from_raw_fd(ret) },
154 })
155 }
156 }
157}
158
159impl AsRawFd for EventFd {
160 fn as_raw_fd(&self) -> RawFd {
161 self.eventfd.as_raw_fd()
162 }
163}
164
165impl FromRawFd for EventFd {
166 unsafe fn from_raw_fd(fd: RawFd) -> Self {
167 EventFd {
168 eventfd: File::from_raw_fd(fd),
169 }
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn test_new() {
179 EventFd::new(EFD_NONBLOCK).unwrap();
180 EventFd::new(0).unwrap();
181 }
182
183 #[test]
184 fn test_read_write() {
185 let evt = EventFd::new(EFD_NONBLOCK).unwrap();
186 evt.write(55).unwrap();
187 assert_eq!(evt.read().unwrap(), 55);
188 }
189
190 #[test]
191 fn test_write_overflow() {
192 let evt = EventFd::new(EFD_NONBLOCK).unwrap();
193 evt.write(std::u64::MAX - 1).unwrap();
194 let r = evt.write(1);
195 match r {
196 Err(ref inner) if inner.kind() == io::ErrorKind::WouldBlock => (),
197 _ => panic!("Unexpected"),
198 }
199 }
200 #[test]
201 fn test_read_nothing() {
202 let evt = EventFd::new(EFD_NONBLOCK).unwrap();
203 let r = evt.read();
204 match r {
205 Err(ref inner) if inner.kind() == io::ErrorKind::WouldBlock => (),
206 _ => panic!("Unexpected"),
207 }
208 }
209 #[test]
210 fn test_clone() {
211 let evt = EventFd::new(EFD_NONBLOCK).unwrap();
212 let evt_clone = evt.try_clone().unwrap();
213 evt.write(923).unwrap();
214 assert_eq!(evt_clone.read().unwrap(), 923);
215 }
216}