fix(windows): use CoWaitForMultipleHandles for ARM64 WebView2 deadlock#1666
Open
npiesco wants to merge 1 commit intotauri-apps:devfrom
Open
fix(windows): use CoWaitForMultipleHandles for ARM64 WebView2 deadlock#1666npiesco wants to merge 1 commit intotauri-apps:devfrom
npiesco wants to merge 1 commit intotauri-apps:devfrom
Conversation
On Windows ARM64 (e.g. Snapdragon X Elite), creating a second WebView2 controller from the main STA thread deadlocked in MsgWaitForMultipleObjectsEx because the nested GetMessage/PeekMessage loop prevented COM from re-entering the apartment to deliver the async completion callback. Replace the mpsc::channel + wait_with_pump pattern in create_environment(), create_controller(), and cookies_inner() with CoWaitForMultipleHandles using COWAIT_DISPATCH_CALLS | COWAIT_DISPATCH_WINDOW_MESSAGES -- the COM-sanctioned mechanism for yielding an STA thread while preserving re-entrancy. Includes unit and integration tests for the new co_wait_for_handle primitive, the Arc<Mutex<Option<T>>> delivery pattern, COWAIT_DISPATCH_CALLS flag acceptance, and the full create_environment/create_controller paths. Ref: https://github.com/npiesco/wry-arm64-deadlock (minimal reproduction)
Legend-Master
requested changes
Feb 15, 2026
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.
Summary
Replaces
mpsc::channel+wait_with_pumppattern withCoWaitForMultipleHandlesin three WebView2 call sites, fixing deterministic deadlock on Windows ARM64 and latent reentrancy issue on all architectures.Closes #1665. Related: #583.
Problem
On Windows ARM64 (Snapdragon X Elite,
aarch64-pc-windows-msvc), creating second WebView2 controller from main STA thread deadlocks insideMsgWaitForMultipleObjectsEx. Root cause is thatwebview2_com::wait_with_pumpruns nested Win32 message pump (GetMessage/PeekMessage), which does not allow COM to re-enter apartment to deliver async completion callbacks. On x86/x64 this usually works by accident because WebView2's internal RPC piggybacks on window messages, but on ARM64 timing exposes bug deterministically.Root cause behind #583 (deadlock creating new window from an IPC handler), which was worked around but never fixed at source.
Solution
Replace all three
mpsc::channel+wait_with_pumpcall sites with:ust CoWaitForMultipleHandles( COWAIT_DISPATCH_CALLS | COWAIT_DISPATCH_WINDOW_MESSAGES, INFINITE, &[event], )COM-sanctioned mechanism for yielding STA thread while preserving reentrancy:
COWAIT_DISPATCH_CALLSdispatches incoming COM calls (required for WebView2 async completion callbacks)COWAIT_DISPATCH_WINDOW_MESSAGESdispatches window messages (keeps the event loop responsive)Approach is consistent with Microsoft's WebView2 threading model documentation on reentrancy.
Design notes
mpsc::channel: previous pattern usedmpsc::channel+wait_with_pump(and comments explained whywait_for_asyncwas avoided). PR removes approach entirely because underlying Win32 message pump prevents COM STA reentrancy, exact mechanism WebView2 needs to deliver completion callbacks.Rc<RefCell<_>>instead ofArc<Mutex<_>>: completion callbacks run on same STA thread (dispatched byCoWaitForMultipleHandles), soRc/RefCellis correct COM types inside aren'tSend/Sync.Win32_Securityfeature gate: Required bywindowscrate'sCreateEventWsignature (SECURITY_ATTRIBUTES). Verified won't compile without it.Affected call sites
create_environment()CreateCoreWebView2EnvironmentWithOptionscreate_controller()CreateCoreWebView2Controller/CreateCoreWebView2ControllerWithOptionscookies_inner()CookieManager().GetCookiesTesting
co_wait_for_handlebehavior, theRc<RefCell<Option<T>>>+ event signaling pattern, STA reentrancy dispatch, and fullcreate_environment/create_controllerintegrationcargo testpasses (8 passed, 0 failed)cargo clippyclean (0 warnings)#[cfg(target_os = windows)])Minimal Reproduction
https://github.com/npiesco/wry-arm64-deadlock
mainbranch: deadlocks on ARM64 (uses upstream wry)fix/vendored-wry-tauribranch: works (uses patched wry fork)