Skip to content

Conversation

@npiesco
Copy link

@npiesco npiesco commented Feb 8, 2026

Summary

Replaces mpsc::channel + wait_with_pump pattern with CoWaitForMultipleHandles in 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 inside MsgWaitForMultipleObjectsEx. Root cause is that webview2_com::wait_with_pump runs 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_pump call 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_CALLS dispatches incoming COM calls (required for WebView2 async completion callbacks)
  • COWAIT_DISPATCH_WINDOW_MESSAGES dispatches window messages (keeps the event loop responsive)

Approach is consistent with Microsoft's WebView2 threading model documentation on reentrancy.

Design notes

  • Intentional departure from mpsc::channel: previous pattern used mpsc::channel + wait_with_pump (and comments explained why wait_for_async was 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 of Arc<Mutex<_>>: completion callbacks run on same STA thread (dispatched by CoWaitForMultipleHandles), so Rc/RefCell is correct COM types inside aren't Send/Sync.
  • Win32_Security feature gate: Required by windows crate's CreateEventW signature (SECURITY_ATTRIBUTES). Verified won't compile without it.
  • Fixes all architectures: ARM64 just exposed bug deterministically; reentrancy problem exists on x86/x64 too (see Deadlock creating a new window on the IPC handler on Windows #583).

Affected call sites

  1. create_environment() CreateCoreWebView2EnvironmentWithOptions
  2. create_controller() CreateCoreWebView2Controller / CreateCoreWebView2ControllerWithOptions
  3. cookies_inner() CookieManager().GetCookies

Testing

  • 6 unit tests added covering co_wait_for_handle behavior, the Rc<RefCell<Option<T>>> + event signaling pattern, STA reentrancy dispatch, and full create_environment/create_controller integration
  • cargo test passes (8 passed, 0 failed)
  • cargo clippy clean (0 warnings)
  • Tested on Windows ARM64 (Snapdragon X Elite) deadlock resolved
  • Tested on WSL2/Linux zero regressions (webview2 module is #[cfg(target_os = windows)])

Minimal Reproduction

https://github.com/npiesco/wry-arm64-deadlock

  • main branch: deadlocks on ARM64 (uses upstream wry)
  • fix/vendored-wry-tauri branch: works (uses patched wry fork)

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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] WebView2 deadlock on ARM64 (and potential reentrancy issue on all architectures)

1 participant