mio/sys/unix/selector/
epoll.rs1use std::io;
2use std::os::fd::{AsFd, AsRawFd, BorrowedFd, 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 AsFd for Selector {
115 fn as_fd(&self) -> BorrowedFd<'_> {
116 self.ep.as_fd()
117 }
118}
119
120impl AsRawFd for Selector {
121 fn as_raw_fd(&self) -> RawFd {
122 self.ep.as_raw_fd()
123 }
124}
125
126fn interests_to_epoll(interests: Interest) -> u32 {
127 let mut kind = EPOLLET;
128
129 if interests.is_readable() {
130 kind = kind | EPOLLIN | EPOLLRDHUP;
131 }
132
133 if interests.is_writable() {
134 kind |= EPOLLOUT;
135 }
136
137 if interests.is_priority() {
138 kind |= EPOLLPRI;
139 }
140
141 kind as u32
142}
143
144pub type Event = libc::epoll_event;
145pub type Events = Vec<Event>;
146
147pub mod event {
148 use std::fmt;
149
150 use crate::sys::Event;
151 use crate::Token;
152
153 pub fn token(event: &Event) -> Token {
154 Token(event.u64 as usize)
155 }
156
157 pub fn is_readable(event: &Event) -> bool {
158 (event.events as libc::c_int & libc::EPOLLIN) != 0
159 || (event.events as libc::c_int & libc::EPOLLPRI) != 0
160 }
161
162 pub fn is_writable(event: &Event) -> bool {
163 (event.events as libc::c_int & libc::EPOLLOUT) != 0
164 }
165
166 pub fn is_error(event: &Event) -> bool {
167 (event.events as libc::c_int & libc::EPOLLERR) != 0
168 }
169
170 pub fn is_read_closed(event: &Event) -> bool {
171 event.events as libc::c_int & libc::EPOLLHUP != 0
173 || (event.events as libc::c_int & libc::EPOLLIN != 0
175 && event.events as libc::c_int & libc::EPOLLRDHUP != 0)
176 }
177
178 pub fn is_write_closed(event: &Event) -> bool {
179 event.events as libc::c_int & libc::EPOLLHUP != 0
181 || (event.events as libc::c_int & libc::EPOLLOUT != 0
183 && event.events as libc::c_int & libc::EPOLLERR != 0)
184 || event.events as libc::c_int == libc::EPOLLERR
186 }
187
188 pub fn is_priority(event: &Event) -> bool {
189 (event.events as libc::c_int & libc::EPOLLPRI) != 0
190 }
191
192 pub fn is_aio(_: &Event) -> bool {
193 false
195 }
196
197 pub fn is_lio(_: &Event) -> bool {
198 false
200 }
201
202 pub fn debug_details(f: &mut fmt::Formatter<'_>, event: &Event) -> fmt::Result {
203 #[allow(clippy::trivially_copy_pass_by_ref)]
204 fn check_events(got: &u32, want: &libc::c_int) -> bool {
205 (*got as libc::c_int & want) != 0
206 }
207 debug_detail!(
208 EventsDetails(u32),
209 check_events,
210 libc::EPOLLIN,
211 libc::EPOLLPRI,
212 libc::EPOLLOUT,
213 libc::EPOLLRDNORM,
214 libc::EPOLLRDBAND,
215 libc::EPOLLWRNORM,
216 libc::EPOLLWRBAND,
217 libc::EPOLLMSG,
218 libc::EPOLLERR,
219 libc::EPOLLHUP,
220 libc::EPOLLET,
221 libc::EPOLLRDHUP,
222 libc::EPOLLONESHOT,
223 libc::EPOLLEXCLUSIVE,
224 libc::EPOLLWAKEUP,
225 libc::EPOLL_CLOEXEC,
226 );
227
228 let e_u64 = event.u64;
230 f.debug_struct("epoll_event")
231 .field("events", &EventsDetails(event.events))
232 .field("u64", &e_u64)
233 .finish()
234 }
235}
236
237pub(crate) use crate::sys::unix::waker::Waker;
239
240cfg_io_source! {
241 mod stateless_io_source;
242 pub(crate) use stateless_io_source::IoSourceState;
243}