From c4924fba7902c381c6ec35a0e9f5d655c5e8fd11 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Thu, 21 May 2026 11:06:54 +0700 Subject: [PATCH] Workaround epoll edge cases --- src/header/poll/mod.rs | 63 ++++++++++++++++++++++--------------- src/platform/redox/epoll.rs | 61 ++++++++++++++++++++++------------- 2 files changed, 78 insertions(+), 46 deletions(-) diff --git a/src/header/poll/mod.rs b/src/header/poll/mod.rs index 59ab527828..83dac36306 100644 --- a/src/header/poll/mod.rs +++ b/src/header/poll/mod.rs @@ -5,19 +5,19 @@ use core::{mem, ptr, slice}; use crate::{ + error::Errno, fs::File, header::{ bits_sigset_t::sigset_t, - errno::EBADF, + errno::{EBADF, EINTR}, sys_epoll::{ EPOLL_CLOEXEC, EPOLL_CTL_ADD, EPOLLERR, EPOLLHUP, EPOLLIN, EPOLLNVAL, EPOLLOUT, - EPOLLPRI, EPOLLRDBAND, EPOLLRDNORM, EPOLLWRBAND, EPOLLWRNORM, epoll_create1, epoll_ctl, - epoll_data, epoll_event, epoll_pwait, + EPOLLPRI, EPOLLRDBAND, EPOLLRDNORM, EPOLLWRBAND, EPOLLWRNORM, epoll_data, epoll_event, }, time::timespec, }, platform::{ - self, + ERRNO, PalEpoll, Sys, types::{c_int, c_short, c_ulong}, }, }; @@ -77,10 +77,13 @@ pub unsafe fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sig ]; let ep = { - let epfd = epoll_create1(EPOLL_CLOEXEC); - if epfd < 0 { - return -1; - } + let epfd = match Sys::epoll_create1(EPOLL_CLOEXEC) { + Ok(epfd) => epfd, + Err(Errno(err)) => { + ERRNO.set(err); + return -1; + } + }; File::new(epfd) }; @@ -108,11 +111,14 @@ pub unsafe fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sig } } - if unsafe { epoll_ctl(*ep, EPOLL_CTL_ADD, pfd.fd, &raw mut event) } < 0 { - if platform::ERRNO.get() == EBADF { + match unsafe { Sys::epoll_ctl(*ep, EPOLL_CTL_ADD, pfd.fd, &raw mut event) } { + Ok(_) => {} + Err(Errno(EBADF)) => { pfd.revents |= POLLNVAL; closed += 1; - } else { + } + Err(Errno(err)) => { + ERRNO.set(err); return -1; } } @@ -124,29 +130,36 @@ pub unsafe fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sig } let mut events: [epoll_event; 32] = unsafe { mem::zeroed() }; - let res = unsafe { - epoll_pwait( + match unsafe { + Sys::epoll_pwait( *ep, events.as_mut_ptr(), events.len() as c_int, timeout, sigmask, ) - }; - if res < 0 { - return -1; - } - - for event in events.iter().take(res as usize) { - let pi = unsafe { event.data.u64 as usize }; - // TODO: Error status when fd does not match? - if let Some(pfd) = fds.get_mut(pi) { - for (p, ep) in event_map.iter() { - if event.events & ep > 0 { - pfd.revents |= p; + } { + Ok(res) => { + for event in events.iter().take(res) { + let pi = unsafe { event.data.u64 as usize }; + // TODO: Error status when fd does not match? + if let Some(pfd) = fds.get_mut(pi) { + for (p, ep) in event_map.iter() { + if event.events & ep > 0 { + pfd.revents |= p; + } + } } } } + Err(Errno(err)) => { + if err == EINTR && closed > 0 { + // some fds are closed by signal + } else { + ERRNO.set(err); + return -1; + } + } } let mut count = 0; diff --git a/src/platform/redox/epoll.rs b/src/platform/redox/epoll.rs index 060b645767..afcd8aafb2 100644 --- a/src/platform/redox/epoll.rs +++ b/src/platform/redox/epoll.rs @@ -10,6 +10,7 @@ use crate::{ io::prelude::*, }; use core::{mem, slice}; +use log::warn; use syscall::{ data::{Event, TimeSpec}, flag::EVENT_READ, @@ -103,27 +104,21 @@ impl PalEpoll for Sys { } let timer_opt = if timeout != -1 { - let mut timer = File::open(c"/scheme/time/4".into(), O_RDWR)?; - Sys::write( - epfd, - &Event { - id: timer.fd as usize, - flags: EVENT_READ, - data: 0, - }, - )?; - - let mut time = TimeSpec::default(); - let _ = timer - .read(&mut time) - .map_err(|err| Errno(err.raw_os_error().unwrap_or(EIO)))?; - time.tv_sec += (timeout as i64) / 1000; - time.tv_nsec += (timeout % 1000) * 1000000; - let _ = timer - .write(&time) - .map_err(|err| Errno(err.raw_os_error().unwrap_or(EIO)))?; - - Some(timer) + // TODO: Any of syscall inside this can fail, there's a race condition on kernel reusing fd numbers + let mut i = 10; + loop { + match register_timeout(epfd, timeout) { + Ok(timer) => break Some(timer), + Err(_) if i > 0 => { + i += 1; + continue; + } + Err(_) => { + warn!("Gave up writing timeout for epoll"); + break None; + } + } + } } else { None }; @@ -174,3 +169,27 @@ impl PalEpoll for Sys { Ok(count) } } + +fn register_timeout(epfd: i32, timeout: i32) -> Result { + let mut timer = File::open(c"/scheme/time/4".into(), O_RDWR)?; + if let Err(e) = Sys::write( + epfd, + &Event { + id: timer.fd as usize, + flags: EVENT_READ, + data: 0, + }, + ) { + return Err(e); + } + let mut time = TimeSpec::default(); + let _ = timer + .read(&mut time) + .map_err(|err| Errno(err.raw_os_error().unwrap_or(EIO)))?; + time.tv_sec += (timeout as i64) / 1000; + time.tv_nsec += (timeout % 1000) * 1000000; + let _ = timer + .write(&time) + .map_err(|err| Errno(err.raw_os_error().unwrap_or(EIO)))?; + Ok(timer) +}