1 use crate::errno::Errno;
2 pub use crate::poll_timeout::PollTimeout as EpollTimeout;
3 use crate::Result;
4 use libc::{self, c_int};
5 use std::mem;
6 use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd};
7 
8 libc_bitflags!(
9     pub struct EpollFlags: c_int {
10         EPOLLIN;
11         EPOLLPRI;
12         EPOLLOUT;
13         EPOLLRDNORM;
14         EPOLLRDBAND;
15         EPOLLWRNORM;
16         EPOLLWRBAND;
17         EPOLLMSG;
18         EPOLLERR;
19         EPOLLHUP;
20         EPOLLRDHUP;
21         EPOLLEXCLUSIVE;
22         #[cfg(not(target_arch = "mips"))]
23         EPOLLWAKEUP;
24         EPOLLONESHOT;
25         EPOLLET;
26     }
27 );
28 
29 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
30 #[repr(i32)]
31 #[non_exhaustive]
32 pub enum EpollOp {
33     EpollCtlAdd = libc::EPOLL_CTL_ADD,
34     EpollCtlDel = libc::EPOLL_CTL_DEL,
35     EpollCtlMod = libc::EPOLL_CTL_MOD,
36 }
37 
38 libc_bitflags! {
39     pub struct EpollCreateFlags: c_int {
40         EPOLL_CLOEXEC;
41     }
42 }
43 
44 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
45 #[repr(transparent)]
46 pub struct EpollEvent {
47     event: libc::epoll_event,
48 }
49 
50 impl EpollEvent {
new(events: EpollFlags, data: u64) -> Self51     pub fn new(events: EpollFlags, data: u64) -> Self {
52         EpollEvent {
53             event: libc::epoll_event {
54                 events: events.bits() as u32,
55                 u64: data,
56             },
57         }
58     }
59 
empty() -> Self60     pub fn empty() -> Self {
61         unsafe { mem::zeroed::<EpollEvent>() }
62     }
63 
events(&self) -> EpollFlags64     pub fn events(&self) -> EpollFlags {
65         EpollFlags::from_bits(self.event.events as c_int).unwrap()
66     }
67 
data(&self) -> u6468     pub fn data(&self) -> u64 {
69         self.event.u64
70     }
71 }
72 
73 /// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html).
74 /// ```
75 /// # use nix::sys::{epoll::{EpollTimeout, Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{EventFd, EfdFlags}};
76 /// # use nix::unistd::write;
77 /// # use std::os::unix::io::{OwnedFd, FromRawFd, AsFd};
78 /// # use std::time::{Instant, Duration};
79 /// # fn main() -> nix::Result<()> {
80 /// const DATA: u64 = 17;
81 /// const MILLIS: u8 = 100;
82 ///
83 /// // Create epoll
84 /// let epoll = Epoll::new(EpollCreateFlags::empty())?;
85 ///
86 /// // Create eventfd & Add event
87 /// let eventfd = EventFd::new()?;
88 /// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?;
89 ///
90 /// // Arm eventfd & Time wait
91 /// eventfd.arm()?;
92 /// let now = Instant::now();
93 ///
94 /// // Wait on event
95 /// let mut events = [EpollEvent::empty()];
96 /// epoll.wait(&mut events, MILLIS)?;
97 ///
98 /// // Assert data correct & timeout didn't occur
99 /// assert_eq!(events[0].data(), DATA);
100 /// assert!(now.elapsed().as_millis() < MILLIS.into());
101 /// # Ok(())
102 /// # }
103 /// ```
104 #[derive(Debug)]
105 pub struct Epoll(pub OwnedFd);
106 impl Epoll {
107     /// Creates a new epoll instance and returns a file descriptor referring to that instance.
108     ///
109     /// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html).
new(flags: EpollCreateFlags) -> Result<Self>110     pub fn new(flags: EpollCreateFlags) -> Result<Self> {
111         let res = unsafe { libc::epoll_create1(flags.bits()) };
112         let fd = Errno::result(res)?;
113         let owned_fd = unsafe { OwnedFd::from_raw_fd(fd) };
114         Ok(Self(owned_fd))
115     }
116     /// Add an entry to the interest list of the epoll file descriptor for
117     /// specified in events.
118     ///
119     /// [`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<()>120     pub fn add<Fd: AsFd>(&self, fd: Fd, mut event: EpollEvent) -> Result<()> {
121         self.epoll_ctl(EpollOp::EpollCtlAdd, fd, &mut event)
122     }
123     /// Remove (deregister) the target file descriptor `fd` from the interest list.
124     ///
125     /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` .
delete<Fd: AsFd>(&self, fd: Fd) -> Result<()>126     pub fn delete<Fd: AsFd>(&self, fd: Fd) -> Result<()> {
127         self.epoll_ctl(EpollOp::EpollCtlDel, fd, None)
128     }
129     /// Change the settings associated with `fd` in the interest list to the new settings specified
130     /// in `event`.
131     ///
132     /// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`.
modify<Fd: AsFd>( &self, fd: Fd, event: &mut EpollEvent, ) -> Result<()>133     pub fn modify<Fd: AsFd>(
134         &self,
135         fd: Fd,
136         event: &mut EpollEvent,
137     ) -> Result<()> {
138         self.epoll_ctl(EpollOp::EpollCtlMod, fd, event)
139     }
140     /// Waits for I/O events, blocking the calling thread if no events are currently available.
141     /// (This can be thought of as fetching items from the ready list of the epoll instance.)
142     ///
143     /// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
wait<T: Into<EpollTimeout>>( &self, events: &mut [EpollEvent], timeout: T, ) -> Result<usize>144     pub fn wait<T: Into<EpollTimeout>>(
145         &self,
146         events: &mut [EpollEvent],
147         timeout: T,
148     ) -> Result<usize> {
149         let res = unsafe {
150             libc::epoll_wait(
151                 self.0.as_raw_fd(),
152                 events.as_mut_ptr().cast(),
153                 events.len() as c_int,
154                 timeout.into().into(),
155             )
156         };
157 
158         Errno::result(res).map(|r| r as usize)
159     }
160     /// This system call is used to add, modify, or remove entries in the interest list of the epoll
161     /// instance referred to by `self`. It requests that the operation `op` be performed for the
162     /// target file descriptor, `fd`.
163     ///
164     /// When possible prefer [`Epoll::add`], [`Epoll::delete`] and [`Epoll::modify`].
165     ///
166     /// [`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>>,167     fn epoll_ctl<'a, Fd: AsFd, T>(
168         &self,
169         op: EpollOp,
170         fd: Fd,
171         event: T,
172     ) -> Result<()>
173     where
174         T: Into<Option<&'a mut EpollEvent>>,
175     {
176         let event: Option<&mut EpollEvent> = event.into();
177         let ptr = event
178             .map(|x| &mut x.event as *mut libc::epoll_event)
179             .unwrap_or(std::ptr::null_mut());
180         unsafe {
181             Errno::result(libc::epoll_ctl(
182                 self.0.as_raw_fd(),
183                 op as c_int,
184                 fd.as_fd().as_raw_fd(),
185                 ptr,
186             ))
187             .map(drop)
188         }
189     }
190 }
191 
192 #[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")]
193 #[inline]
epoll_create() -> Result<RawFd>194 pub fn epoll_create() -> Result<RawFd> {
195     let res = unsafe { libc::epoll_create(1024) };
196 
197     Errno::result(res)
198 }
199 
200 #[deprecated(since = "0.27.0", note = "Use Epoll::new() instead")]
201 #[inline]
epoll_create1(flags: EpollCreateFlags) -> Result<RawFd>202 pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
203     let res = unsafe { libc::epoll_create1(flags.bits()) };
204 
205     Errno::result(res)
206 }
207 
208 #[deprecated(since = "0.27.0", note = "Use Epoll::epoll_ctl() instead")]
209 #[inline]
epoll_ctl<'a, T>( epfd: RawFd, op: EpollOp, fd: RawFd, event: T, ) -> Result<()> where T: Into<Option<&'a mut EpollEvent>>,210 pub fn epoll_ctl<'a, T>(
211     epfd: RawFd,
212     op: EpollOp,
213     fd: RawFd,
214     event: T,
215 ) -> Result<()>
216 where
217     T: Into<Option<&'a mut EpollEvent>>,
218 {
219     let mut event: Option<&mut EpollEvent> = event.into();
220     if event.is_none() && op != EpollOp::EpollCtlDel {
221         Err(Errno::EINVAL)
222     } else {
223         let res = unsafe {
224             if let Some(ref mut event) = event {
225                 libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
226             } else {
227                 libc::epoll_ctl(epfd, op as c_int, fd, std::ptr::null_mut())
228             }
229         };
230         Errno::result(res).map(drop)
231     }
232 }
233 
234 #[deprecated(since = "0.27.0", note = "Use Epoll::wait() instead")]
235 #[inline]
epoll_wait( epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize, ) -> Result<usize>236 pub fn epoll_wait(
237     epfd: RawFd,
238     events: &mut [EpollEvent],
239     timeout_ms: isize,
240 ) -> Result<usize> {
241     let res = unsafe {
242         libc::epoll_wait(
243             epfd,
244             events.as_mut_ptr().cast(),
245             events.len() as c_int,
246             timeout_ms as c_int,
247         )
248     };
249 
250     Errno::result(res).map(|r| r as usize)
251 }
252