1use super::epoll_uring::EPOLL_URING_STATE;
7use super::epoll_uring::EPOLL_URING_TOKEN;
8use super::epoll_uring::EpollIoUring;
9use super::epoll_uring::EpollUringThreadState;
10use super::wait::FdWait;
11use crate::fd::FdReadyDriver;
12use crate::fd::PollFdReady;
13use crate::interest::InterestSlot;
14use crate::interest::PollEvents;
15use crate::interest::PollInterestSet;
16use crate::io_pool::IoBackend;
17use crate::io_pool::IoDriver;
18use crate::io_pool::IoPool;
19use crate::timer::Instant;
20use crate::timer::PollTimer;
21use crate::timer::TimerDriver;
22use crate::timer::TimerQueue;
23use crate::timer::TimerQueueId;
24use crate::timer::TimerResult;
25use crate::wait::WaitDriver;
26use crate::waker::WakerList;
27use futures::FutureExt;
28use futures::task::ArcWake;
29use futures::task::waker_ref;
30use once_cell::sync::OnceCell;
31use pal::unix::Errno;
32use pal::unix::SyscallResult;
33use pal::unix::while_eintr;
34use pal_event::Event;
35use parking_lot::Mutex;
36use std::fs::File;
37use std::future::Future;
38use std::io;
39use std::os::unix::prelude::*;
40use std::pin::pin;
41use std::sync::Arc;
42use std::task::Context;
43use std::task::Poll;
44
45pub type EpollPool = IoPool<EpollBackend>;
47
48pub type EpollDriver = IoDriver<EpollBackend>;
50
51pub type WeakEpollDriver = crate::io_pool::WeakIoDriver<EpollBackend>;
53
54#[derive(Debug)]
55pub struct EpollBackend {
56 epfd: EpollFd,
57 wake_event: Event,
58 state: Mutex<EpollState>,
59 io_uring: OnceCell<EpollIoUring>,
60}
61
62impl Default for EpollBackend {
63 fn default() -> Self {
64 let epfd = EpollFd::new().expect("epoll not functional");
65 let wake_event = Event::new();
66 epfd.add(
70 wake_event.as_fd().as_raw_fd(),
71 libc::EPOLLIN | libc::EPOLLET,
72 0,
73 )
74 .expect("could not add wake event");
75 Self {
76 epfd,
77 wake_event,
78 state: Mutex::new(EpollState {
79 state: PoolState::Running,
80 timers: TimerQueue::default(),
81 fd_ready_to_delete: Vec::new(),
82 }),
83 io_uring: OnceCell::new(),
84 }
85 }
86}
87
88#[derive(Debug)]
89struct EpollState {
90 state: PoolState,
91 timers: TimerQueue,
92 fd_ready_to_delete: Vec<Arc<FdReadyOp>>,
93}
94
95#[derive(Debug)]
96enum PoolState {
97 Running,
98 RunAgain,
99 Sleeping(Option<Instant>),
100 Waking,
101}
102
103impl PoolState {
104 fn reset(&mut self) {
105 match self {
106 PoolState::Running => {}
107 PoolState::RunAgain => {}
108 PoolState::Sleeping(_) => unreachable!(),
109 PoolState::Waking => {}
110 }
111 *self = PoolState::Running;
112 }
113
114 #[must_use]
116 fn wake(&mut self) -> bool {
117 match self {
118 PoolState::Running => {
119 *self = PoolState::RunAgain;
120 false
121 }
122 PoolState::RunAgain => false,
123 PoolState::Sleeping(_) => {
124 *self = PoolState::Waking;
125 true
126 }
127 PoolState::Waking => false,
128 }
129 }
130
131 fn can_sleep(&self) -> bool {
132 match self {
133 PoolState::Running => true,
134 PoolState::RunAgain => false,
135 PoolState::Sleeping(_) => unreachable!(),
136 PoolState::Waking => unreachable!(),
137 }
138 }
139
140 fn sleep(&mut self, deadline: Option<Instant>) {
141 match self {
142 PoolState::Running => {}
143 PoolState::RunAgain => unreachable!(),
144 PoolState::Sleeping(_) => unreachable!(),
145 PoolState::Waking => unreachable!(),
146 }
147 *self = PoolState::Sleeping(deadline);
148 }
149
150 #[must_use]
152 fn wake_for_timer(&mut self, deadline: Instant) -> bool {
153 match self {
154 PoolState::Running => false,
155 PoolState::RunAgain => false,
156 PoolState::Waking => false,
157 &mut PoolState::Sleeping(Some(current_deadline)) if current_deadline <= deadline => {
158 false
159 }
160 PoolState::Sleeping(_) => {
161 *self = PoolState::Waking;
162 true
163 }
164 }
165 }
166
167 fn is_referencing_ops(&self) -> bool {
168 match self {
169 PoolState::Running => false,
170 PoolState::RunAgain => false,
171 PoolState::Sleeping(_) => true,
172 PoolState::Waking => true,
173 }
174 }
175}
176
177impl IoBackend for EpollBackend {
178 fn name() -> &'static str {
179 "epoll"
180 }
181
182 fn run<Fut: Future>(self: &Arc<Self>, fut: Fut) -> Fut::Output {
183 let mut fut = pin!(fut);
184
185 let waker = waker_ref(self);
186 let mut cx = Context::from_waker(&waker);
187
188 let mut to_delete: Vec<_> = Vec::new();
189 let mut wakers = WakerList::default();
190
191 let uring_thread_state = EpollUringThreadState::new(std::ptr::null());
195
196 EPOLL_URING_STATE.with(|cell| {
197 cell.lend(&uring_thread_state, || {
198 let mut state = self.state.lock();
199 loop {
200 state.state.reset();
201
202 state.timers.wake_expired(&mut wakers);
204 drop(state);
205
206 if let Some(uring) = self.io_uring.get() {
211 unsafe { uring_thread_state.set_ring(uring) }
214 .process_completions(&mut wakers);
215 }
216
217 wakers.wake();
218 to_delete.clear();
219
220 match fut.poll_unpin(&mut cx) {
221 Poll::Ready(r) => break r,
222 Poll::Pending => {}
223 }
224
225 state = self.state.lock();
226 assert!(state.fd_ready_to_delete.is_empty());
228
229 if state.state.can_sleep() {
230 let deadline = state.timers.next_deadline();
231 state.state.sleep(deadline);
232 drop(state);
233
234 if let Some(uring) = self.io_uring.get() {
239 unsafe { uring_thread_state.set_ring(uring) }.flush();
242 }
243
244 let timeout = deadline
245 .map(|deadline| {
246 let now = Instant::now();
247 (deadline.max(now) - now)
248 .as_millis()
249 .try_into()
250 .unwrap_or(i32::MAX)
251 })
252 .unwrap_or(-1);
253
254 let mut events = [libc::epoll_event { events: 0, u64: 0 }; 8];
255 let n = while_eintr(|| self.epfd.wait(&mut events, timeout))
256 .expect("epoll_wait failed unexpectedly");
257
258 let _ = self.state.lock().state.wake();
260
261 for event in &events[..n] {
262 if event.u64 == 0 {
263 self.wake_event.try_wait();
264 } else if event.u64 == EPOLL_URING_TOKEN {
265 } else {
268 let op = unsafe { &*(event.u64 as usize as *const FdReadyOp) };
277 op.wake_ready(event.events, &mut wakers);
278 }
279 }
280
281 state = self.state.lock();
282
283 to_delete.append(&mut state.fd_ready_to_delete);
285 }
286 }
287 }) }) }
290}
291
292#[derive(Debug)]
293struct EpollFd(File);
294
295impl EpollFd {
296 fn new() -> Result<Self, Errno> {
297 let epfd = unsafe {
299 File::from_raw_fd(libc::epoll_create1(libc::EPOLL_CLOEXEC).syscall_result()?)
300 };
301 Ok(Self(epfd))
302 }
303
304 fn add(&self, fd: RawFd, events: i32, context: u64) -> Result<(), Errno> {
305 let mut event = libc::epoll_event {
306 events: events as u32,
307 u64: context,
308 };
309 unsafe {
311 libc::epoll_ctl(self.0.as_raw_fd(), libc::EPOLL_CTL_ADD, fd, &mut event)
312 .syscall_result()?;
313 }
314 Ok(())
315 }
316
317 fn del(&self, fd: RawFd) -> Result<(), Errno> {
318 unsafe {
320 libc::epoll_ctl(
321 self.0.as_raw_fd(),
322 libc::EPOLL_CTL_DEL,
323 fd,
324 std::ptr::null_mut(),
325 )
326 .syscall_result()?;
327 }
328 Ok(())
329 }
330
331 fn wait(&self, events: &mut [libc::epoll_event], timeout: i32) -> Result<usize, Errno> {
332 let maxevents = events.len() as i32;
333 let n = unsafe {
335 libc::epoll_wait(self.0.as_raw_fd(), events.as_mut_ptr(), maxevents, timeout)
336 .syscall_result()?
337 };
338 Ok(n as usize)
339 }
340}
341
342impl ArcWake for EpollBackend {
343 fn wake_by_ref(arc_self: &Arc<Self>) {
344 let wake = arc_self.state.lock().state.wake();
345 if wake {
346 arc_self.wake_event.signal();
347 }
348 }
349}
350
351#[derive(Debug)]
352pub struct FdReady {
353 op: Arc<FdReadyOp>,
354 epoll: Arc<EpollBackend>,
355 fd: RawFd,
356}
357
358#[derive(Debug)]
359struct FdReadyOp {
360 inner: Mutex<FdReadyInner>,
361}
362
363#[derive(Debug)]
364struct FdReadyInner {
365 interests: PollInterestSet,
366}
367
368impl FdReadyOp {
369 fn wake_ready(&self, ep_events: u32, wakers: &mut WakerList) {
370 let revents = PollEvents::from_epoll_events(ep_events);
371 self.inner.lock().interests.wake_ready(revents, wakers)
372 }
373}
374
375impl FdReadyDriver for EpollDriver {
376 type FdReady = FdReady;
377
378 fn new_fd_ready(&self, fd: RawFd) -> io::Result<Self::FdReady> {
379 let op = Arc::new(FdReadyOp {
380 inner: Mutex::new(FdReadyInner {
381 interests: PollInterestSet::default(),
382 }),
383 });
384 self.inner.epfd.add(
385 fd,
386 libc::EPOLLET | libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLPRI | libc::EPOLLRDHUP,
387 Arc::as_ptr(&op) as usize as u64,
388 )?;
389 let _ = Arc::into_raw(op.clone());
391
392 Ok(FdReady {
393 op,
394 epoll: self.inner.clone(),
395 fd,
396 })
397 }
398}
399
400impl Drop for FdReady {
401 fn drop(&mut self) {
402 self.epoll
413 .epfd
414 .del(self.fd)
415 .expect("epoll_ctl unexpectedly failed");
416
417 let op = unsafe { Arc::from_raw(Arc::as_ptr(&self.op)) };
419 let mut state = self.epoll.state.lock();
420 if state.state.is_referencing_ops() {
421 state.fd_ready_to_delete.push(op);
422 if state.state.wake() {
423 drop(state);
424 self.epoll.wake_event.signal();
425 }
426 }
427 }
428}
429
430impl PollFdReady for FdReady {
431 fn poll_fd_ready(
432 &mut self,
433 cx: &mut Context<'_>,
434 slot: InterestSlot,
435 events: PollEvents,
436 ) -> Poll<PollEvents> {
437 self.op.inner.lock().interests.poll_ready(cx, slot, events)
438 }
439
440 fn clear_fd_ready(&mut self, slot: InterestSlot) {
441 self.op.inner.lock().interests.clear_ready(slot)
442 }
443}
444
445impl WaitDriver for EpollDriver {
446 type Wait = FdWait<FdReady>;
447
448 fn new_wait(&self, fd: RawFd, read_size: usize) -> io::Result<Self::Wait> {
449 Ok(FdWait::new(fd, self.new_fd_ready(fd)?, read_size))
450 }
451}
452
453impl TimerDriver for EpollDriver {
454 type Timer = Timer;
455
456 fn new_timer(&self) -> Self::Timer {
457 let id = self.inner.state.lock().timers.add();
458 Timer {
459 epoll: self.inner.clone(),
460 id,
461 }
462 }
463}
464
465impl crate::io_uring::IoUringDriver for EpollDriver {
466 type Submitter = EpollIoUring;
467
468 fn io_uring_submitter(&self) -> Option<&EpollIoUring> {
469 self.inner
470 .io_uring
471 .get_or_try_init(|| {
472 EpollIoUring::new(
473 self.inner.epfd.0.as_raw_fd(),
474 self.inner.wake_event.as_fd().as_raw_fd(),
475 )
476 })
477 .ok()
478 }
479}
480
481#[derive(Debug)]
482pub struct Timer {
483 epoll: Arc<EpollBackend>,
484 id: TimerQueueId,
485}
486
487impl Drop for Timer {
488 fn drop(&mut self) {
489 let _waker = self.epoll.state.lock().timers.remove(self.id);
490 }
491}
492
493impl PollTimer for Timer {
494 fn poll_timer(&mut self, cx: &mut Context<'_>, deadline: Option<Instant>) -> Poll<Instant> {
495 let mut state = self.epoll.state.lock();
496 if let Some(deadline) = deadline {
497 state.timers.set_deadline(self.id, deadline);
498 }
499 match state.timers.poll_deadline(cx, self.id) {
500 TimerResult::TimedOut(now) => Poll::Ready(now),
501 TimerResult::Pending(deadline) => {
502 if state.state.wake_for_timer(deadline) {
503 drop(state);
504 self.epoll.wake_event.signal();
505 }
506 Poll::Pending
507 }
508 }
509 }
510
511 fn set_deadline(&mut self, deadline: Instant) {
512 let mut state = self.epoll.state.lock();
513 if state.timers.set_deadline(self.id, deadline) && state.state.wake_for_timer(deadline) {
514 drop(state);
515 self.epoll.wake_event.signal();
516 }
517 }
518}
519
520#[cfg(test)]
521mod tests {
522 use super::EpollPool;
523 use crate::executor_tests;
524
525 #[test]
526 fn waker_works() {
527 EpollPool::run_with(|_| executor_tests::waker_tests())
528 }
529
530 #[test]
531 fn spawn_works() {
532 executor_tests::spawn_tests(|| {
533 let pool = EpollPool::new();
534 (pool.driver(), move || pool.run())
535 })
536 }
537
538 #[test]
539 fn sleep_works() {
540 EpollPool::run_with(executor_tests::sleep_tests)
541 }
542
543 #[test]
544 fn wait_works() {
545 EpollPool::run_with(executor_tests::wait_tests)
546 }
547
548 #[test]
549 fn socket_works() {
550 EpollPool::run_with(executor_tests::socket_tests)
551 }
552
553 #[test]
554 fn process_works() {
555 EpollPool::run_with(executor_tests::process_tests)
556 }
557
558 #[test]
559 fn uring_works() {
560 EpollPool::run_with(executor_tests::io_uring_tests::uring_tests)
561 }
562}