Skip to main content

kevy_sys/
poller_ep.rs

1//! Linux epoll-backed `Poller`. Wired by `lib.rs` via a cfg-gated
2//! `pub use`. The macOS / iOS kqueue twin lives in [`crate::poller_kq`].
3
4use core::ffi::c_int;
5use std::io;
6use std::ptr;
7
8use crate::{Event, WAIT_CAPACITY, ffi};
9
10mod ep {
11    pub const EPOLL_CLOEXEC: super::c_int = 0x80000;
12    pub const EPOLL_CTL_ADD: super::c_int = 1;
13    pub const EPOLL_CTL_DEL: super::c_int = 2;
14    pub const EPOLL_CTL_MOD: super::c_int = 3;
15    pub const EPOLLIN: u32 = 0x001;
16    pub const EPOLLOUT: u32 = 0x004;
17    pub const EPOLLERR: u32 = 0x008;
18    pub const EPOLLHUP: u32 = 0x010;
19    pub const EPOLLRDHUP: u32 = 0x2000;
20}
21
22pub struct Poller {
23    epfd: c_int,
24}
25
26impl Poller {
27    pub fn new() -> io::Result<Self> {
28        let epfd = unsafe { ffi::epoll_create1(ep::EPOLL_CLOEXEC) };
29        if epfd < 0 {
30            return Err(io::Error::last_os_error());
31        }
32        Ok(Poller { epfd })
33    }
34
35    fn mask(read: bool, write: bool) -> u32 {
36        let mut m = ep::EPOLLRDHUP;
37        if read {
38            m |= ep::EPOLLIN;
39        }
40        if write {
41            m |= ep::EPOLLOUT;
42        }
43        m
44    }
45
46    fn ctl(&self, op: c_int, fd: i32, read: bool, write: bool) -> io::Result<()> {
47        let mut ev = ffi::EpollEvent {
48            events: Self::mask(read, write),
49            data: fd as u64,
50        };
51        let r = unsafe { ffi::epoll_ctl(self.epfd, op, fd, &mut ev) };
52        if r < 0 {
53            return Err(io::Error::last_os_error());
54        }
55        Ok(())
56    }
57
58    pub fn add(&self, fd: i32, read: bool, write: bool) -> io::Result<()> {
59        self.ctl(ep::EPOLL_CTL_ADD, fd, read, write)
60    }
61
62    pub fn modify(&self, fd: i32, read: bool, write: bool) -> io::Result<()> {
63        self.ctl(ep::EPOLL_CTL_MOD, fd, read, write)
64    }
65
66    pub fn delete(&self, fd: i32) -> io::Result<()> {
67        let r = unsafe { ffi::epoll_ctl(self.epfd, ep::EPOLL_CTL_DEL, fd, ptr::null_mut()) };
68        if r < 0 {
69            return Err(io::Error::last_os_error());
70        }
71        Ok(())
72    }
73
74    pub fn wait(&self, out: &mut Vec<Event>, timeout_ms: Option<i32>) -> io::Result<usize> {
75        out.clear();
76        let mut raw: Vec<ffi::EpollEvent> = Vec::with_capacity(WAIT_CAPACITY);
77        let n = unsafe {
78            ffi::epoll_wait(
79                self.epfd,
80                raw.as_mut_ptr(),
81                WAIT_CAPACITY as c_int,
82                timeout_ms.unwrap_or(-1),
83            )
84        };
85        if n < 0 {
86            let e = io::Error::last_os_error();
87            if e.kind() == io::ErrorKind::Interrupted {
88                return Ok(0);
89            }
90            return Err(e);
91        }
92        unsafe { raw.set_len(n as usize) };
93        for ev in &raw {
94            let flags = ev.events; // copy out (struct may be packed on x86_64)
95            let fd = ev.data as i32;
96            let hup = flags & (ep::EPOLLHUP | ep::EPOLLERR | ep::EPOLLRDHUP) != 0;
97            out.push(Event {
98                fd,
99                readable: flags & (ep::EPOLLIN | ep::EPOLLHUP | ep::EPOLLERR) != 0,
100                writable: flags & ep::EPOLLOUT != 0,
101                hup,
102            });
103        }
104        Ok(out.len())
105    }
106}
107
108impl Drop for Poller {
109    fn drop(&mut self) {
110        unsafe {
111            ffi::close(self.epfd);
112        }
113    }
114}