nix/sys/
epoll.rs

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