From f5b9000c5d723915366a29283ab4e436018631ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 24 Jul 2026 11:30:20 -0400 Subject: [PATCH] fix(cgroup): stop swallowing inotify read errors in the memory monitor wait_and_drain treated every read() <= 0 as "queue drained", so a real error (bad fd, EINVAL) silently ended the drain and the monitor kept polling a broken fd. Distinguish the cases: EAGAIN ends the drain, EINTR retries, and any other error propagates. monitor_loop logs the error before exiting so a dead memory monitor is visible in the session log. --- .../kigi-tools/src/computer/local/cgroup.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/codegen/kigi-tools/src/computer/local/cgroup.rs b/crates/codegen/kigi-tools/src/computer/local/cgroup.rs index 56dbb1b..6afd6f1 100644 --- a/crates/codegen/kigi-tools/src/computer/local/cgroup.rs +++ b/crates/codegen/kigi-tools/src/computer/local/cgroup.rs @@ -127,8 +127,8 @@ mod linux { async fn wait_and_drain(&self) -> std::io::Result<()> { let mut guard = self.fd.readable().await?; - // Drain all pending inotify events; the fd is non-blocking, so the - // read returns <= 0 once the queue is empty. + // Drain all pending inotify events so the next readiness wakeup + // corresponds to a fresh modification. let mut buf = [0u8; 4096]; loop { // SAFETY: writing at most `buf.len()` bytes into `buf`, through @@ -143,7 +143,16 @@ mod linux { if n > 0 { continue; } - break; + if n == 0 { + break; + } + let err = std::io::Error::last_os_error(); + match err.kind() { + // The fd is non-blocking: the queue is empty. + std::io::ErrorKind::WouldBlock => break, + std::io::ErrorKind::Interrupted => continue, + _ => return Err(err), + } } guard.clear_ready(); Ok(()) @@ -304,7 +313,10 @@ mod linux { let mut last_high_count = Self::read_high_counter(&events_path).await.unwrap_or(0); loop { - if inotify.wait_and_drain().await.is_err() { + if let Err(e) = inotify.wait_and_drain().await { + tracing::warn!( + "memory.events inotify read failed; stopping memory monitor: {e}" + ); break; }