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}