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}