From 415fa3c8c21319883f081809dc429674600138b6 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Fri, 17 Jul 2026 00:31:27 +0900 Subject: [PATCH] epoll: retry EPOLL_CTL_ADD/MOD on transient EINVAL/EBADF (Redox) Registering an fd with /scheme/event can transiently fail with EINVAL/EBADF while the scheme backing the fd is still starting up or the fd table is churning during early boot (e.g. a tokio/mio reactor built by a daemon that races ahead of ipcd's uds_stream scheme). Without recovery, tokio's Runtime::build aborts the whole runtime with "Invalid argument (os error 22)", killing every zbus daemon (sessiond, polkit, udisks, upower) and any tokio program including the login shell. Retry the /scheme/event registration write with a 5ms backoff, up to ~2s, on EINVAL/EBADF; a genuinely permanent failure still surfaces after the bounded window. Redox-only. This is the registration-site counterpart to the existing park-path recovery in the P0-epoll-redox-recovery tokio patch. --- src/platform/redox/epoll.rs | 47 +++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/src/platform/redox/epoll.rs b/src/platform/redox/epoll.rs index 8c0b2d17b7..b9dd7597ea 100644 --- a/src/platform/redox/epoll.rs +++ b/src/platform/redox/epoll.rs @@ -57,16 +57,43 @@ impl PalEpoll for Sys { ) -> Result<(), Errno> { match op { EPOLL_CTL_ADD | EPOLL_CTL_MOD => { - Sys::write( - epfd, - &Event { - id: fd as usize, - flags: unsafe { epoll_to_event_flags((*event).events) }, - // NOTE: Danger when using something smaller than 64-bit - // systems. If this is needed, use a box or something - data: unsafe { (*event).data.u64 as usize }, - }, - )?; + let ev = Event { + id: fd as usize, + flags: unsafe { epoll_to_event_flags((*event).events) }, + // NOTE: Danger when using something smaller than 64-bit + // systems. If this is needed, use a box or something + data: unsafe { (*event).data.u64 as usize }, + }; + // Registering an fd with /scheme/event can transiently fail + // with EINVAL/EBADF while the scheme backing `fd` is still + // starting up or the fd-table is churning during early boot + // (e.g. a tokio/mio reactor built by a daemon that races ahead + // of ipcd's uds_stream scheme). Without recovery, tokio's + // Runtime::build aborts the whole runtime, killing every + // zbus-based daemon and any tokio program (including the login + // shell). Retry with a short backoff so the registration + // succeeds once the scheme settles; a genuinely permanent + // failure still surfaces after the bounded window. This mirrors + // the park-path recovery in the P0-epoll-redox-recovery tokio + // patch, but at the registration site the patch cannot reach. + let mut attempts: u32 = 0; + loop { + match Sys::write(epfd, &ev) { + Ok(_) => break, + Err(Errno(err)) + if (err == EINVAL || err == EBADF) && attempts < 400 => + { + attempts += 1; + let req = syscall::data::TimeSpec { + tv_sec: 0, + tv_nsec: 5_000_000, // 5ms; up to ~2s total + }; + let mut rem = syscall::data::TimeSpec::default(); + let _ = syscall::nanosleep(&req, &mut rem); + } + Err(err) => return Err(err), + } + } } EPOLL_CTL_DEL => { Sys::write(