nix/sys/
epoll.rs

1use crate::errno::Errno;
2pub use crate::poll_timeout::PollTimeout as EpollTimeout;
3use crate::Result;
4use libc::{self, c_int};
5use std::mem;
6use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd};
7
8libc_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]
32pub enum EpollOp {
33    EpollCtlAdd = libc::EPOLL_CTL_ADD,
34    EpollCtlDel = libc::EPOLL_CTL_DEL,
35    EpollCtlMod = libc::EPOLL_CTL_MOD,
36}
37
38libc_bitflags! {
39    pub struct EpollCreateFlags: c_int {
40        EPOLL_CLOEXEC;
41    }
42}
43
44#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
45#[repr(transparent)]
46pub struct EpollEvent {
47    event: libc::epoll_event,
48}
49
50impl EpollEvent {
51    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
60    pub fn empty() -> Self {
61        unsafe { mem::zeroed::<EpollEvent>() }
62    }
63
64    pub fn events(&self) -> EpollFlags {
65        EpollFlags::from_bits(self.event.events as c_int).unwrap()
66    }
67
68    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)]
105pub struct Epoll(pub OwnedFd);
106impl 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).
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`.
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` .
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`.
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)
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)
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]
194pub 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]
202pub 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]
210pub fn epoll_ctl<'a, T>(
211    epfd: RawFd,
212    op: EpollOp,
213    fd: RawFd,
214    event: T,
215) -> Result<()>
216where
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]
236pub 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}