diff options
-rw-r--r-- | clang-tools-extra/clangd/ClangdLSPServer.cpp | 8 | ||||
-rw-r--r-- | clang-tools-extra/clangd/ClangdLSPServer.h | 6 | ||||
-rw-r--r-- | clang-tools-extra/clangd/tool/ClangdMain.cpp | 23 |
3 files changed, 29 insertions, 8 deletions
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index 3f825a6febd..9e24878dc8f 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -1231,7 +1231,11 @@ ClangdLSPServer::ClangdLSPServer( // clang-format on } -ClangdLSPServer::~ClangdLSPServer() { IsBeingDestroyed = true; } +ClangdLSPServer::~ClangdLSPServer() { IsBeingDestroyed = true; + // Explicitly destroy ClangdServer first, blocking on threads it owns. + // This ensures they don't access any other members. + Server.reset(); +} bool ClangdLSPServer::run() { // Run the Language Server loop. @@ -1241,8 +1245,6 @@ bool ClangdLSPServer::run() { CleanExit = false; } - // Destroy ClangdServer to ensure all worker threads finish. - Server.reset(); return CleanExit && ShutdownRequestReceived; } diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h index dbd90064537..f1ed317f6ba 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -44,6 +44,7 @@ public: llvm::Optional<Path> CompileCommandsDir, bool UseDirBasedCDB, llvm::Optional<OffsetEncoding> ForcedOffsetEncoding, const ClangdServer::Options &Opts); + /// The destructor blocks on any outstanding background tasks. ~ClangdLSPServer(); /// Run LSP server loop, communicating with the Transport provided in the @@ -211,11 +212,10 @@ private: std::unique_ptr<GlobalCompilationDatabase> BaseCDB; // CDB is BaseCDB plus any comands overridden via LSP extensions. llvm::Optional<OverlayCDB> CDB; - // The ClangdServer is created by the "initialize" LSP method. - // It is destroyed before run() returns, to ensure worker threads exit. ClangdServer::Options ClangdServerOpts; - llvm::Optional<ClangdServer> Server; llvm::Optional<OffsetEncoding> NegotiatedOffsetEncoding; + // The ClangdServer is created by the "initialize" LSP method. + llvm::Optional<ClangdServer> Server; }; } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 4cb6604072a..2639df31dbe 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include <chrono> #include <cstdlib> #include <iostream> #include <memory> @@ -670,6 +671,24 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var /*UseDirBasedCDB=*/CompileArgsFrom == FilesystemCompileArgs, OffsetEncodingFromFlag, Opts); llvm::set_thread_name("clangd.main"); - return LSPServer.run() ? 0 - : static_cast<int>(ErrorResultCode::NoShutdownRequest); + int ExitCode = LSPServer.run() + ? 0 + : static_cast<int>(ErrorResultCode::NoShutdownRequest); + log("LSP finished, exiting with status {0}", ExitCode); + + // There may still be lingering background threads (e.g. slow requests + // whose results will be dropped, background index shutting down). + // + // These should terminate quickly, and ~ClangdLSPServer blocks on them. + // However if a bug causes them to run forever, we want to ensure the process + // eventually exits. As clangd isn't directly user-facing, an editor can + // "leak" clangd processes. Crashing in this case contains the damage. + // + // This is more portable than sys::WatchDog, and yields a stack trace. + std::thread([] { + std::this_thread::sleep_for(std::chrono::minutes(5)); + std::abort(); + }).detach(); + + return ExitCode; } |