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:
+37
-10
@@ -57,16 +57,43 @@ impl PalEpoll for Sys {
|
|||||||
) -> Result<(), Errno> {
|
) -> Result<(), Errno> {
|
||||||
match op {
|
match op {
|
||||||
EPOLL_CTL_ADD | EPOLL_CTL_MOD => {
|
EPOLL_CTL_ADD | EPOLL_CTL_MOD => {
|
||||||
Sys::write(
|
let ev = Event {
|
||||||
epfd,
|
id: fd as usize,
|
||||||
&Event {
|
flags: unsafe { epoll_to_event_flags((*event).events) },
|
||||||
id: fd as usize,
|
// NOTE: Danger when using something smaller than 64-bit
|
||||||
flags: unsafe { epoll_to_event_flags((*event).events) },
|
// systems. If this is needed, use a box or something
|
||||||
// NOTE: Danger when using something smaller than 64-bit
|
data: unsafe { (*event).data.u64 as usize },
|
||||||
// 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 => {
|
EPOLL_CTL_DEL => {
|
||||||
Sys::write(
|
Sys::write(
|
||||||
|
|||||||
Reference in New Issue
Block a user