Skip to content

/windbg-user-mutex-held-across-co-await

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.

BOOST
From plugin
win-dev-skills
46611 skills2 agents
Install
$ npx -y skills add microsoft/win-dev-skills --skill windbg-user-mutex-held-across-co-await --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/windbg-user-mutex-held-across-co-await

Context preview

The summary Claude sees to decide when to auto-load this skill.

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.

SKILL.md

windbg-user-mutex-held-across-co-await.SKILL.md
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:

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.

Read more
Ships withwin-dev-skills

Agent plugins for Windows development and debugging—from apps and services to kernel-mode drivers—with GitHub Copilot, Claude Code, OpenAI Codex, and more. Add this repo as a marketplace once, then install the plugins you need.

Get the whole plugin, auto-invoked

Other skills on win-dev-skills.