From 55adf85aa7a49ae9b76d9e4df6b378eacca63208 Mon Sep 17 00:00:00 2001 From: John Tur Date: Tue, 28 Apr 2026 10:19:03 +0200 Subject: [PATCH] Fix process teardown deadlock on Windows (#55065) AWS-LC registers an `atexit` handler that intentionally acquires a lock without releasing it. AWS-LC also has `thread_local` objects which acquire this lock in their destructor. Destructors for `thread_local`s run under the loader lock. So, there is a race condition where, if a thread exits after `atexit` handlers have run, the TLS destructors will block indefinitely on this lock while holding the loader lock. Since `ExitProcess` also requires the loader lock, process teardown will deadlock. Closes #54856 Release Notes: - Fixed an issue where the Zed process wouldn't exit after closing all windows --- crates/gpui_windows/src/platform.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/gpui_windows/src/platform.rs b/crates/gpui_windows/src/platform.rs index 7e9f1e7748..4c28982562 100644 --- a/crates/gpui_windows/src/platform.rs +++ b/crates/gpui_windows/src/platform.rs @@ -410,6 +410,17 @@ impl Platform for WindowsPlatform { self.inner .with_callback(|callbacks| &callbacks.quit, |callback| callback()); + + // Bypass the CRT exit logic, which runs atexit handlers before calling ExitProcess. + // aws-lc registers an atexit handler that intentionally acquires a lock without releasing it. + // aws-lc also has thread_local objects which acquire this lock in their destructor. + // Destructors for thread_locals run under the loader lock, so there is a race condition + // where, if a thread exits after atexit handlers have run, the TLS destructors will block + // indefinitely on this lock while holding the loader lock. Since ExitProcess also requires + // the loader lock, process teardown will deadlock. + unsafe { + windows::Win32::System::Threading::ExitProcess(0); + } } fn quit(&self) {