mio/sys/unix/selector/
epoll.rs1use std::io;
2use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
3#[cfg(debug_assertions)]
4use std::sync::atomic::{AtomicUsize, Ordering};
5use std::time::Duration;
6
7use libc::{EPOLLET, EPOLLIN, EPOLLOUT, EPOLLPRI, EPOLLRDHUP};
8
9use crate::{Interest, Token};
10
11cfg_io_source! {
12    use std::ptr;
13}
14
15#[cfg(debug_assertions)]
17static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
18
19#[derive(Debug)]
20pub struct Selector {
21    #[cfg(debug_assertions)]
22    id: usize,
23    ep: OwnedFd,
24}
25
26impl Selector {
27    pub fn new() -> io::Result<Selector> {
28        let ep = unsafe { OwnedFd::from_raw_fd(syscall!(epoll_create1(libc::EPOLL_CLOEXEC))?) };
30        Ok(Selector {
31            #[cfg(debug_assertions)]
32            id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
33            ep,
34        })
35    }
36
37    pub fn try_clone(&self) -> io::Result<Selector> {
38        self.ep.try_clone().map(|ep| Selector {
39            #[cfg(debug_assertions)]
41            id: self.id,
42            ep,
43        })
44    }
45
46    pub fn select(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<()> {
47        let timeout = timeout
48            .map(|to| {
49                to.checked_add(Duration::from_nanos(999_999))
54                    .unwrap_or(to)
55                    .as_millis() as libc::c_int
56            })
57            .unwrap_or(-1);
58
59        events.clear();
60        syscall!(epoll_wait(
61            self.ep.as_raw_fd(),
62            events.as_mut_ptr(),
63            events.capacity() as i32,
64            timeout,
65        ))
66        .map(|n_events| {
67            unsafe { events.set_len(n_events as usize) };
70        })
71    }
72
73    pub fn register(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
74        let mut event = libc::epoll_event {
75            events: interests_to_epoll(interests),
76            u64: usize::from(token) as u64,
77            #[cfg(target_os = "redox")]
78            _pad: 0,
79        };
80
81        let ep = self.ep.as_raw_fd();
82        syscall!(epoll_ctl(ep, libc::EPOLL_CTL_ADD, fd, &mut event)).map(|_| ())
83    }
84
85    cfg_any_os_ext! {
86    pub fn reregister(&self, fd: RawFd, token: Token, interests: Interest) -> io::Result<()> {
87        let mut event = libc::epoll_event {
88            events: interests_to_epoll(interests),
89            u64: usize::from(token) as u64,
90            #[cfg(target_os = "redox")]
91            _pad: 0,
92        };
93
94        let ep = self.ep.as_raw_fd();
95        syscall!(epoll_ctl(ep, libc::EPOLL_CTL_MOD, fd, &mut event)).map(|_| ())
96    }
97
98    pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
99        let ep = self.ep.as_raw_fd();
100        syscall!(epoll_ctl(ep, libc::EPOLL_CTL_DEL, fd, ptr::null_mut())).map(|_| ())
101    }
102    }
103}
104
105cfg_io_source! {
106    impl Selector {
107        #[cfg(debug_assertions)]
108        pub fn id(&self) -> usize {
109            self.id
110        }
111    }
112}
113
114impl AsRawFd for Selector {
115    fn as_raw_fd(&self) -> RawFd {
116        self.ep.as_raw_fd()
117    }
118}
119
120fn interests_to_epoll(interests: Interest) -> u32 {
121    let mut kind = EPOLLET;
122
123    if interests.is_readable() {
124        kind = kind | EPOLLIN | EPOLLRDHUP;
125    }
126
127    if interests.is_writable() {
128        kind |= EPOLLOUT;
129    }
130
131    if interests.is_priority() {
132        kind |= EPOLLPRI;
133    }
134
135    kind as u32
136}
137
138pub type Event = libc::epoll_event;
139pub type Events = Vec<Event>;
140
141pub mod event {
142    use std::fmt;
143
144    use crate::sys::Event;
145    use crate::Token;
146
147    pub fn token(event: &Event) -> Token {
148        Token(event.u64 as usize)
149    }
150
151    pub fn is_readable(event: &Event) -> bool {
152        (event.events as libc::c_int & libc::EPOLLIN) != 0
153            || (event.events as libc::c_int & libc::EPOLLPRI) != 0
154    }
155
156    pub fn is_writable(event: &Event) -> bool {
157        (event.events as libc::c_int & libc::EPOLLOUT) != 0
158    }
159
160    pub fn is_error(event: &Event) -> bool {
161        (event.events as libc::c_int & libc::EPOLLERR) != 0
162    }
163
164    pub fn is_read_closed(event: &Event) -> bool {
165        event.events as libc::c_int & libc::EPOLLHUP != 0
167            || (event.events as libc::c_int & libc::EPOLLIN != 0
169                && event.events as libc::c_int & libc::EPOLLRDHUP != 0)
170    }
171
172    pub fn is_write_closed(event: &Event) -> bool {
173        event.events as libc::c_int & libc::EPOLLHUP != 0
175            || (event.events as libc::c_int & libc::EPOLLOUT != 0
177                && event.events as libc::c_int & libc::EPOLLERR != 0)
178            || event.events as libc::c_int == libc::EPOLLERR
180    }
181
182    pub fn is_priority(event: &Event) -> bool {
183        (event.events as libc::c_int & libc::EPOLLPRI) != 0
184    }
185
186    pub fn is_aio(_: &Event) -> bool {
187        false
189    }
190
191    pub fn is_lio(_: &Event) -> bool {
192        false
194    }
195
196    pub fn debug_details(f: &mut fmt::Formatter<'_>, event: &Event) -> fmt::Result {
197        #[allow(clippy::trivially_copy_pass_by_ref)]
198        fn check_events(got: &u32, want: &libc::c_int) -> bool {
199            (*got as libc::c_int & want) != 0
200        }
201        debug_detail!(
202            EventsDetails(u32),
203            check_events,
204            libc::EPOLLIN,
205            libc::EPOLLPRI,
206            libc::EPOLLOUT,
207            libc::EPOLLRDNORM,
208            libc::EPOLLRDBAND,
209            libc::EPOLLWRNORM,
210            libc::EPOLLWRBAND,
211            libc::EPOLLMSG,
212            libc::EPOLLERR,
213            libc::EPOLLHUP,
214            libc::EPOLLET,
215            libc::EPOLLRDHUP,
216            libc::EPOLLONESHOT,
217            libc::EPOLLEXCLUSIVE,
218            libc::EPOLLWAKEUP,
219            libc::EPOLL_CLOEXEC,
220        );
221
222        let e_u64 = event.u64;
224        f.debug_struct("epoll_event")
225            .field("events", &EventsDetails(event.events))
226            .field("u64", &e_u64)
227            .finish()
228    }
229}
230
231pub(crate) use crate::sys::unix::waker::Waker;
233
234cfg_io_source! {
235    mod stateless_io_source;
236    pub(crate) use stateless_io_source::IoSourceState;
237}