Fix LSP thread hang on exit on Windows#6196
Merged
aryairani merged 9 commits intounisonweb:trunkfrom Mar 30, 2026
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3487
Problem
On Windows, typing
exitorquitin a UCM shell session would cause the terminal to hang, requiring a manualCtrl+Cto kill the process. This was caused by the GHC Windows I/O manager being unable to deliver async exceptions to threads blocked in a socketacceptcall. When the UCM CLI exited,Ki.scopedwould try to cancel and join the LSP thread, but the LSP thread was blocked inTCP.servewaiting for a connection and would never wake up.As a workaround, the LSP was disabled by default on Windows behind a
UNISON_LSP_ENABLED=trueenvironment variable flag.Fix
Instead of using
TCP.serve(which owns the socket internally), we now manually bind the socket withTCP.bindSockso we can hold a reference to it. The socket is passed back toMain.hsvia a callback. After the UCM CLI exits,Main.hscloses the socket, which unblocks theacceptcall at the OS level and allows the LSP thread to exit cleanly on all platforms.A
shutdownVarflag is set before the accept loop starts. WhenhandleFailurecatches anIOExceptionduring shutdown, it checks this flag and suppresses the misleading "LSP server failed to start" message. All other error cases should be unaffected, since onlyIOExceptionis caught here, and only the error message is suppressed, not any other behavior.With the exit hang fixed, the
UNISON_LSP_ENABLEDWindows guard inifEnabledhas been removed, enabling LSP on Windows by default.Result
UCM now exits cleanly on Windows without hanging, and the LSP server starts by default on Windows, allowing the VS Code extension to connect without any additional configuration.