From ac4cea35e0a313c907f4f00ae7f251b8ded6934d Mon Sep 17 00:00:00 2001 From: Rajat Patra Date: Mon, 9 Nov 2026 01:20:01 +0530 Subject: [PATCH] Add timeout to host WSL command to prevent startup freeze run_host_wsl blocks on command.output() with no deadline. When WSL is not installed the stub wsl.exe in System32 hangs for roughly 60 seconds before returning REGDB_E_CLASSNOTREG, freezing the entire app during bootstrap. Replace the blocking call with spawn + poll loop capped at 5 seconds. If wsl.exe does not exit in time it is killed and an error is returned, so list_distributions gracefully fails and the shell list falls back to non-WSL entries. Fixes #788 --- crates/wsl/src/lib.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/crates/wsl/src/lib.rs b/crates/wsl/src/lib.rs index 5ac419a78..319cc4b96 100644 --- a/crates/wsl/src/lib.rs +++ b/crates/wsl/src/lib.rs @@ -17,6 +17,7 @@ const WSL_LOCALHOST_SERVER: &str = "wsl.localhost"; const WSL_LEGACY_SERVER: &str = "wsl$"; const WSLENV: &str = "WSLENV"; const GIT_PROBE_RETRY_INTERVAL: Duration = Duration::from_secs(60); +const HOST_WSL_TIMEOUT: Duration = Duration::from_secs(5); #[cfg(windows)] const CREATE_NO_WINDOW: u32 = 0x0800_0000; @@ -684,11 +685,33 @@ pub fn resolve_windows_path(path: &str) -> Result { fn run_host_wsl(args: &[&str]) -> Result { let mut command = Command::new(WSL_EXE); command.args(args); + command.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped()); hide_console_window(&mut command); - let output = command - .output() + + let mut child = command + .spawn() .map_err(|e| format!("Failed to run {WSL_EXE}: {e}"))?; + let deadline = Instant::now() + HOST_WSL_TIMEOUT; + loop { + match child.try_wait() { + Ok(Some(_)) => break, + Ok(None) => { + if Instant::now() >= deadline { + let _ = child.kill(); + let _ = child.wait(); + return Err(format!("{WSL_EXE} timed out after {HOST_WSL_TIMEOUT:?}")); + } + std::thread::sleep(Duration::from_millis(50)); + } + Err(e) => return Err(format!("Failed to wait for {WSL_EXE}: {e}")), + } + } + + let output = child + .wait_with_output() + .map_err(|e| format!("Failed to read {WSL_EXE} output: {e}"))?; + Ok(CommandOutput { status_success: output.status.success(), stdout: output.stdout,