From 3107ed847a15dc74601fac33731f65a6fa5a9355 Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Thu, 1 Feb 2024 17:49:53 +0100 Subject: [PATCH] lsp: if language server closes stdout/stderr, break loop (#7229) Previously we would run these loops indefinitely when a language server closed its stdout/stderr and the `read_until` returned `0` bytes read. Easy to reproduce: start Zed with LSP attached, `kill -9` the LSP, see logs accumulate. Release Notes: - Fix high CPU usage when a language server crashes (or closes its stdout/stderr on purpose). Co-authored-by: Julia Co-authored-by: Mikayla --- crates/lsp/src/lsp.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index 0d88e1507c7e9c70337a98b05fbb34e26b9acfdd..f9cd138217cfed5d0eb3d409a7bbe8c4fe78e0a3 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -322,8 +322,15 @@ impl LanguageServer { let mut buffer = Vec::new(); loop { buffer.clear(); - stdout.read_until(b'\n', &mut buffer).await?; - stdout.read_until(b'\n', &mut buffer).await?; + + if stdout.read_until(b'\n', &mut buffer).await? == 0 { + break; + }; + + if stdout.read_until(b'\n', &mut buffer).await? == 0 { + break; + }; + let header = std::str::from_utf8(&buffer)?; let message_len: usize = header .strip_prefix(CONTENT_LEN_HEADER) @@ -378,6 +385,8 @@ impl LanguageServer { // Don't starve the main thread when receiving lots of messages at once. smol::future::yield_now().await; } + + Ok(()) } async fn handle_stderr( @@ -393,7 +402,12 @@ impl LanguageServer { loop { buffer.clear(); - stderr.read_until(b'\n', &mut buffer).await?; + + let bytes_read = stderr.read_until(b'\n', &mut buffer).await?; + if bytes_read == 0 { + return Ok(()); + } + if let Ok(message) = str::from_utf8(&buffer) { log::trace!("incoming stderr message:{message}"); for handler in io_handlers.lock().values_mut() {