From e6ea8ace6d02fedfed22aaa3dd36f34ebc007c48 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Thu, 12 Mar 2026 12:30:45 -0500 Subject: [PATCH] conhost: Unlock the console while tearing down during coniosrv focus evt (#19967) With the rendering thread changes in #18632 and #19330, we strengthened a requirement that render shutdown be done outside of the console lock. This works on all platforms except OneCore, where ConIoSrv manages the focus of multiple console windows and we need to explicitly order the handling of tearing down and relinquishing device resources. The old code (before #18632) used to wait for a whole second before giving up. Instead, let's just unlock the console to let the final frame drain out. I created a synthetic repro: start two cmd sessions with a lot of rendering load (`cmdd start cmd /c dir /s c:\`), and then run `cmdd date /t` in a tight loop while tabbing between the console windows. Before this fix, it hangs within a couple tens of date invocations. With this fix, it does not hang at all. Fixes MSFT-61354695 --- src/interactivity/onecore/ConIoSrvComm.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/interactivity/onecore/ConIoSrvComm.cpp b/src/interactivity/onecore/ConIoSrvComm.cpp index ca002a0982..bfb7a6be1b 100644 --- a/src/interactivity/onecore/ConIoSrvComm.cpp +++ b/src/interactivity/onecore/ConIoSrvComm.cpp @@ -444,7 +444,15 @@ VOID ConIoSrvComm::HandleFocusEvent(const CIS_EVENT* const Event) // TODO: MSFT: 11833883 - Determine action when wait on paint operation via // DirectX on OneCoreUAP times out while switching console // applications. + + UnlockConsole(); + // Teardown may need to wait for an entire frame to finish, but it will not be + // able to do so while we are holding the console lock. Relinquish the lock + // for as long as it takes to quiesce the render thread, and then take it back + // afterwards. This is globally safe because ConIoSrv will not process any other + // requests while the focus event is outstanding. Renderer->TriggerTeardown(); + LockConsole(); // Relinquish control of the graphics device (only one // DirectX application may control the device at any one