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.
This commit is contained in:
Red Bear OS
2026-07-17 00:31:27 +09:00
parent ab699eaa50
commit 415fa3c8c2
+37 -10
View File
@@ -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(