• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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 
5 use std::mem;
6 use std::os::unix::io::AsFd;
7 use std::os::unix::io::AsRawFd;
8 use std::os::unix::io::FromRawFd;
9 use std::os::unix::io::OwnedFd;
10 
11 use libc::c_int;
12 use nix::errno::Errno;
13 use nix::sys::epoll::EpollCreateFlags;
14 use nix::sys::epoll::EpollFlags;
15 use nix::sys::epoll::EpollOp;
16 use nix::Result;
17 
18 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
19 #[repr(transparent)]
20 pub struct EpollEvent {
21     event: libc::epoll_event,
22 }
23 
24 impl EpollEvent {
new(events: EpollFlags, data: u64) -> Self25     pub fn new(events: EpollFlags, data: u64) -> Self {
26         EpollEvent {
27             event: libc::epoll_event {
28                 events: events.bits() as u32,
29                 u64: data,
30             },
31         }
32     }
33 
empty() -> Self34     pub fn empty() -> Self {
35         // SAFETY: trivially safe
36         unsafe { mem::zeroed::<EpollEvent>() }
37     }
38 
events(&self) -> EpollFlags39     pub fn events(&self) -> EpollFlags {
40         EpollFlags::from_bits(self.event.events as c_int).unwrap()
41     }
42 
data(&self) -> u6443     pub fn data(&self) -> u64 {
44         self.event.u64
45     }
46 }
47 
48 // This is a function is unreleased nix 0.27 -- when it is released, we can delete this.
49 #[derive(Debug)]
50 pub struct Epoll(pub OwnedFd);
51 impl Epoll {
52     /// Creates a new epoll instance and returns a file descriptor referring to that instance.
53     ///
54     /// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html).
new(flags: EpollCreateFlags) -> Result<Self>55     pub fn new(flags: EpollCreateFlags) -> Result<Self> {
56         // TODO(b/315870313): Add safety comment
57         #[allow(clippy::undocumented_unsafe_blocks)]
58         let res = unsafe { libc::epoll_create1(flags.bits()) };
59         let fd = Errno::result(res)?;
60         // TODO(b/315870313): Add safety comment
61         #[allow(clippy::undocumented_unsafe_blocks)]
62         let owned_fd = unsafe { OwnedFd::from_raw_fd(fd) };
63         Ok(Self(owned_fd))
64     }
65     /// Add an entry to the interest list of the epoll file descriptor for
66     /// specified in events.
67     ///
68     /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_ADD`.
add<Fd: AsFd>(&self, fd: Fd, mut event: EpollEvent) -> Result<()>69     pub fn add<Fd: AsFd>(&self, fd: Fd, mut event: EpollEvent) -> Result<()> {
70         self.epoll_ctl(EpollOp::EpollCtlAdd, fd, &mut event)
71     }
72     /// Remove (deregister) the target file descriptor `fd` from the interest list.
73     ///
74     /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` .
delete<Fd: AsFd>(&self, fd: Fd) -> Result<()>75     pub fn delete<Fd: AsFd>(&self, fd: Fd) -> Result<()> {
76         self.epoll_ctl(EpollOp::EpollCtlDel, fd, None)
77     }
78     /// Change the settings associated with `fd` in the interest list to the new settings specified
79     /// in `event`.
80     ///
81     /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`.
82     #[allow(dead_code)]
modify<Fd: AsFd>(&self, fd: Fd, event: &mut EpollEvent) -> Result<()>83     pub fn modify<Fd: AsFd>(&self, fd: Fd, event: &mut EpollEvent) -> Result<()> {
84         self.epoll_ctl(EpollOp::EpollCtlMod, fd, event)
85     }
86     /// Waits for I/O events, blocking the calling thread if no events are currently available.
87     /// (This can be thought of as fetching items from the ready list of the epoll instance.)
88     ///
89     /// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
wait(&self, events: &mut [EpollEvent], timeout: isize) -> Result<usize>90     pub fn wait(&self, events: &mut [EpollEvent], timeout: isize) -> Result<usize> {
91         // TODO(b/315870313): Add safety comment
92         #[allow(clippy::undocumented_unsafe_blocks)]
93         let res = unsafe {
94             libc::epoll_wait(
95                 self.0.as_raw_fd(),
96                 events.as_mut_ptr() as *mut libc::epoll_event,
97                 events.len() as c_int,
98                 timeout as c_int,
99             )
100         };
101 
102         Errno::result(res).map(|r| r as usize)
103     }
104     /// This system call is used to add, modify, or remove entries in the interest list of the epoll
105     /// instance referred to by `self`. It requests that the operation `op` be performed for the
106     /// target file descriptor, `fd`.
107     ///
108     /// When possible prefer [`Epoll::add`], [`Epoll::delete`] and [`Epoll::modify`].
109     ///
110     /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
epoll_ctl<'a, Fd: AsFd, T>(&self, op: EpollOp, fd: Fd, event: T) -> Result<()> where T: Into<Option<&'a mut EpollEvent>>,111     fn epoll_ctl<'a, Fd: AsFd, T>(&self, op: EpollOp, fd: Fd, event: T) -> Result<()>
112     where
113         T: Into<Option<&'a mut EpollEvent>>,
114     {
115         let event: Option<&mut EpollEvent> = event.into();
116         let ptr = event
117             .map(|x| &mut x.event as *mut libc::epoll_event)
118             .unwrap_or(std::ptr::null_mut());
119         // TODO(b/315870313): Add safety comment
120         #[allow(clippy::undocumented_unsafe_blocks)]
121         unsafe {
122             Errno::result(libc::epoll_ctl(
123                 self.0.as_raw_fd(),
124                 op as c_int,
125                 fd.as_fd().as_raw_fd(),
126                 ptr,
127             ))
128             .map(drop)
129         }
130     }
131 }
132