---
name: windbg-user-mutex-held-across-co-await
description: 'Use when app, service, or user-mode driver C++ coroutine code holds a thread-affine lock across suspension and later hangs or fails. Not for all coroutine crashes or choosing lock performance.'
---

# Mutex Held Across co_await

**Load `windbg-diagnostic-method` first** if it is not already loaded in this
conversation, and apply it throughout for evidence ranking, hypothesis testing,
confidence calibration, independent review, and report validation. This skill
adds the bug-family-specific commands and evidence requirements.

## Detection

This pattern can occur in native application, service, or user-mode driver
code, including UMDF components that use C++ coroutines. Look for a lock
acquired before `co_await` and released after resumption or
coroutine destruction. Mutex ownership belongs to the acquiring thread, not
the coroutine frame. A resumption on another thread can violate that contract.
Even same-thread resumption can create reentrancy or progress problems when
the awaited operation needs a lock the coroutine still holds.

## Workflow

1. Identify the exact lock primitive and acquisition/release scope in source.
   Audit every suspension point while the RAII guard or ownership is alive.
2. Establish the acquire and resume threads using trace/source evidence.
   Standard mutexes and SRW locks do not provide a universally queryable owner
   field; do not fabricate an owning TID from undocumented layouts.
3. Verify the awaiter's resumption contract. C++/WinRT can preserve apartment
   context for particular awaitables; `resume_background` intentionally switches.
   Do not assume every WinRT awaitable always resumes on a worker or always on
   the originating thread.
4. Distinguish wrong-thread release, a dependency cycle, state changed during
   suspension, lifetime failure, and unrelated memory corruption.
5. Move the thread-affine lock into synchronous scopes. Revalidate relevant
   state after the await rather than treating the pre-await snapshot as current.

If the symptom is general blocking use `windbg-user-wait-chain-analysis`. For damaged
heap objects use `windbg-user-heap-corruption-investigation`. If a recording is available,
`windbg-user-ttd-reverse-debugging-triage` can help establish the ownership timeline.

## Fix pattern

Conceptual sequence, not a promise about any particular scheduler:

```text
under lock:
    take a snapshot and its generation
release lock
await work using that snapshot
under lock on the resumed thread:
    revalidate generation, lifetime, and assumptions
    apply result or explicitly handle a stale/cancelled operation
release lock
```

Use RAII for each synchronous scope. If invariants cannot tolerate unlocking,
redesign the operation or use a specifically designed asynchronous coordination
primitive with cancellation/lifetime rules. Switching to a recursive mutex or
`shared_mutex` does not make a thread-affine lock coroutine-safe.

Do not recommend a blanket mutex-type replacement. Shared locking is a separate
design decision; changing the primitive does not repair suspension ownership.
Keep the object and any captured interfaces alive across asynchronous work.

## Validation

- No thread-affine lock ownership survives a suspension in the corrected path.
- Each awaiter's thread/apartment contract is understood.
- State invariants are revalidated after suspension.
- Cancellation, concurrent mutation, shutdown, and failed awaited work are tested.
- The remedy removes the demonstrated cause, not just an observed exception.

## References

- [Holding a lock across coroutine suspension](https://devblogs.microsoft.com/oldnewthing/20210707-00/?p=105417)
- [C++/WinRT concurrency and asynchronous operations](https://learn.microsoft.com/windows/uwp/cpp-and-winrt-apis/concurrency)
- [Slim reader/writer locks](https://learn.microsoft.com/windows/win32/sync/slim-reader-writer--srw--locks)

## Feedback

Follow `FEEDBACK.md` and report reviewed, sanitized feedback to
[WinDbg-Feedback](https://github.com/microsoft/WinDbg-Feedback/issues).
Include `windbg-user-mutex-held-across-co-await` and the package version from `plugin.json`;
no automatic source, dump, or transcript upload.
