From 97551ba9b9f7e4c19e863c4729b55fde7206e5da Mon Sep 17 00:00:00 2001 From: Yaroslav Volovich Date: Fri, 13 Feb 2026 21:26:03 +0000 Subject: [PATCH] Refine Linux and Windows sleep inhibitor robustness --- codex-rs/Cargo.lock | 2 +- codex-rs/utils/sleep-inhibitor/Cargo.toml | 2 +- .../sleep-inhibitor/src/linux_inhibitor.rs | 93 +++++++++++++++---- .../sleep-inhibitor/src/windows_inhibitor.rs | 10 +- 4 files changed, 83 insertions(+), 24 deletions(-) diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 62b606229c..978ed77ff5 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -2504,7 +2504,7 @@ dependencies = [ "core-foundation 0.9.4", "libc", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/codex-rs/utils/sleep-inhibitor/Cargo.toml b/codex-rs/utils/sleep-inhibitor/Cargo.toml index 9863e8cf66..795c750d50 100644 --- a/codex-rs/utils/sleep-inhibitor/Cargo.toml +++ b/codex-rs/utils/sleep-inhibitor/Cargo.toml @@ -17,7 +17,7 @@ tracing = { workspace = true } [target.'cfg(target_os = "windows")'.dependencies] tracing = { workspace = true } -windows-sys = { version = "0.60.2", features = [ +windows-sys = { version = "0.52", features = [ "Win32_Foundation", "Win32_System_Power", "Win32_System_SystemServices", diff --git a/codex-rs/utils/sleep-inhibitor/src/linux_inhibitor.rs b/codex-rs/utils/sleep-inhibitor/src/linux_inhibitor.rs index 09b3d54332..0e0d369642 100644 --- a/codex-rs/utils/sleep-inhibitor/src/linux_inhibitor.rs +++ b/codex-rs/utils/sleep-inhibitor/src/linux_inhibitor.rs @@ -5,11 +5,15 @@ use tracing::warn; const ASSERTION_REASON: &str = "Codex is running an active turn"; const APP_ID: &str = "codex"; +// Keep the blocker process alive "long enough" without needing restarts. +// This is `i32::MAX` seconds, which is accepted by common `sleep` implementations. const BLOCKER_SLEEP_SECONDS: &str = "2147483647"; #[derive(Debug, Default)] pub(crate) struct LinuxSleepInhibitor { state: InhibitState, + preferred_backend: Option, + missing_backend_logged: bool, } #[derive(Debug, Default)] @@ -36,34 +40,87 @@ impl LinuxSleepInhibitor { impl PlatformSleepInhibitor for LinuxSleepInhibitor { fn acquire(&mut self) { - if let InhibitState::Active { child, .. } = &mut self.state - && child.try_wait().ok().flatten().is_none() - { - return; - } - - self.state = InhibitState::Inactive; - - for backend in [ - LinuxBackend::SystemdInhibit, - LinuxBackend::GnomeSessionInhibit, - ] { - match spawn_backend(backend) { - Ok(child) => { - self.state = InhibitState::Active { backend, child }; - return; + if let InhibitState::Active { backend, child } = &mut self.state { + match child.try_wait() { + Ok(None) => return, + Ok(Some(status)) => { + warn!( + ?backend, + ?status, + "Linux sleep inhibitor backend exited unexpectedly; attempting fallback" + ); } Err(error) => { warn!( ?backend, reason = %error, - "Failed to start Linux sleep inhibitor backend" + "Failed to query Linux sleep inhibitor backend status" ); } } } - warn!("No Linux sleep inhibitor backend is available"); + self.state = InhibitState::Inactive; + let should_log_backend_failures = !self.missing_backend_logged; + let backends = match self.preferred_backend { + Some(LinuxBackend::SystemdInhibit) => [ + LinuxBackend::SystemdInhibit, + LinuxBackend::GnomeSessionInhibit, + ], + Some(LinuxBackend::GnomeSessionInhibit) => [ + LinuxBackend::GnomeSessionInhibit, + LinuxBackend::SystemdInhibit, + ], + None => [ + LinuxBackend::SystemdInhibit, + LinuxBackend::GnomeSessionInhibit, + ], + }; + + for backend in backends { + match spawn_backend(backend) { + Ok(mut child) => match child.try_wait() { + Ok(None) => { + self.state = InhibitState::Active { backend, child }; + self.preferred_backend = Some(backend); + self.missing_backend_logged = false; + return; + } + Ok(Some(status)) => { + if should_log_backend_failures { + warn!( + ?backend, + ?status, + "Linux sleep inhibitor backend exited immediately" + ); + } + } + Err(error) => { + if should_log_backend_failures { + warn!( + ?backend, + reason = %error, + "Failed to query Linux sleep inhibitor backend status after spawn" + ); + } + } + }, + Err(error) => { + if should_log_backend_failures && error.kind() != std::io::ErrorKind::NotFound { + warn!( + ?backend, + reason = %error, + "Failed to start Linux sleep inhibitor backend" + ); + } + } + } + } + + if should_log_backend_failures { + warn!("No Linux sleep inhibitor backend is available"); + self.missing_backend_logged = true; + } } fn release(&mut self) { diff --git a/codex-rs/utils/sleep-inhibitor/src/windows_inhibitor.rs b/codex-rs/utils/sleep-inhibitor/src/windows_inhibitor.rs index a0142c4a33..c83a432af2 100644 --- a/codex-rs/utils/sleep-inhibitor/src/windows_inhibitor.rs +++ b/codex-rs/utils/sleep-inhibitor/src/windows_inhibitor.rs @@ -39,7 +39,7 @@ impl PlatformSleepInhibitor for WindowsSleepInhibitor { } Err(error) => { warn!( - reason = error, + reason = %error, "Failed to acquire Windows sleep-prevention request" ); } @@ -58,7 +58,7 @@ struct PowerRequest { } impl PowerRequest { - fn new_execution_required(reason: &str) -> Result { + fn new_execution_required(reason: &str) -> Result { let mut wide_reason: Vec = OsStr::new(reason).encode_wide().chain(once(0)).collect(); let context = REASON_CONTEXT { Version: POWER_REQUEST_CONTEXT_VERSION, @@ -69,13 +69,15 @@ impl PowerRequest { }; let handle = unsafe { PowerCreateRequest(&context) }; if handle.is_null() { - return Err("PowerCreateRequest failed"); + let error = std::io::Error::last_os_error(); + return Err(format!("PowerCreateRequest failed: {error}")); } let request_type = PowerRequestExecutionRequired; if unsafe { PowerSetRequest(handle, request_type) } == 0 { + let error = std::io::Error::last_os_error(); let _ = unsafe { CloseHandle(handle) }; - return Err("PowerSetRequest failed"); + return Err(format!("PowerSetRequest failed: {error}")); } Ok(Self {