sys_util/
eventfd.rs

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
5use std::fs::File;
6use std::mem;
7use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
8
9use libc::{c_void, dup, eventfd, read, write};
10
11use {errno_result, Result};
12
13/// A safe wrapper around a Linux eventfd (man 2 eventfd).
14///
15/// An eventfd is useful because it is sendable across processes and can be used for signaling in
16/// and out of the KVM API. They can also be polled like any other file descriptor.
17#[derive(Debug)]
18pub struct EventFd {
19    eventfd: File,
20}
21
22impl EventFd {
23    /// Creates a new blocking EventFd with an initial value of 0.
24    pub fn new() -> Result<EventFd> {
25        // This is safe because eventfd merely allocated an eventfd for our process and we handle
26        // the error case.
27        let ret = unsafe { eventfd(0, 0) };
28        if ret < 0 {
29            return errno_result();
30        }
31        // This is safe because we checked ret for success and know the kernel gave us an fd that we
32        // own.
33        Ok(EventFd {
34            eventfd: unsafe { File::from_raw_fd(ret) },
35        })
36    }
37
38    /// Adds `v` to the eventfd's count, blocking until this won't overflow the count.
39    pub fn write(&self, v: u64) -> Result<()> {
40        // This is safe because we made this fd and the pointer we pass can not overflow because we
41        // give the syscall's size parameter properly.
42        let ret = unsafe {
43            write(
44                self.as_raw_fd(),
45                &v as *const u64 as *const c_void,
46                mem::size_of::<u64>(),
47            )
48        };
49        if ret <= 0 {
50            return errno_result();
51        }
52        Ok(())
53    }
54
55    /// Blocks until the the eventfd's count is non-zero, then resets the count to zero.
56    pub fn read(&self) -> Result<u64> {
57        let mut buf: u64 = 0;
58        let ret = unsafe {
59            // This is safe because we made this fd and the pointer we pass can not overflow because
60            // we give the syscall's size parameter properly.
61            read(
62                self.as_raw_fd(),
63                &mut buf as *mut u64 as *mut c_void,
64                mem::size_of::<u64>(),
65            )
66        };
67        if ret <= 0 {
68            return errno_result();
69        }
70        Ok(buf)
71    }
72
73    /// Clones this EventFd, internally creating a new file descriptor. The new EventFd will share
74    /// the same underlying count within the kernel.
75    pub fn try_clone(&self) -> Result<EventFd> {
76        // This is safe because we made this fd and properly check that it returns without error.
77        let ret = unsafe { dup(self.as_raw_fd()) };
78        if ret < 0 {
79            return errno_result();
80        }
81        // This is safe because we checked ret for success and know the kernel gave us an fd that we
82        // own.
83        Ok(EventFd {
84            eventfd: unsafe { File::from_raw_fd(ret) },
85        })
86    }
87}
88
89impl AsRawFd for EventFd {
90    fn as_raw_fd(&self) -> RawFd {
91        self.eventfd.as_raw_fd()
92    }
93}
94
95impl FromRawFd for EventFd {
96    unsafe fn from_raw_fd(fd: RawFd) -> Self {
97        EventFd {
98            eventfd: File::from_raw_fd(fd),
99        }
100    }
101}
102
103impl IntoRawFd for EventFd {
104    fn into_raw_fd(self) -> RawFd {
105        self.eventfd.into_raw_fd()
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn new() {
115        EventFd::new().unwrap();
116    }
117
118    #[test]
119    fn read_write() {
120        let evt = EventFd::new().unwrap();
121        evt.write(55).unwrap();
122        assert_eq!(evt.read(), Ok(55));
123    }
124
125    #[test]
126    fn clone() {
127        let evt = EventFd::new().unwrap();
128        let evt_clone = evt.try_clone().unwrap();
129        evt.write(923).unwrap();
130        assert_eq!(evt_clone.read(), Ok(923));
131    }
132}