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