Skip to content

Fix lock-order inversion deadlock in AsyncCurrentValue#154

Merged
bok- merged 2 commits intomainfrom
fix/asynccurrentvalue-deadlock
May 8, 2026
Merged

Fix lock-order inversion deadlock in AsyncCurrentValue#154
bok- merged 2 commits intomainfrom
fix/asynccurrentvalue-deadlock

Conversation

@bok-
Copy link
Copy Markdown
Contributor

@bok- bok- commented May 8, 2026

📒 Description

The previous implementation resumed pending continuations inside wrappedValue's didSet, which executed within the mutex lock. This created a lock-order inversion when a task cancellation raced a concurrent update: the update thread held the mutex and called continuation.resume() (which internally acquires Swift's task status lock), while the cancelling thread held the task status lock and entered the onCancel: handler (which attempted to acquire the mutex). Neither thread could proceed.

The fix moves continuation resumption outside the mutex. The update method now atomically captures the updated value, bumped generation, and pending continuations inside the lock, then resumes continuations after releasing it. No continuation can miss a generation because the registration and extraction of continuations happen within the same lock closure — any continuation arriving after the extraction will see the already-bumped generation and return immediately.

Fixes #153.

🗳 Test Plan

A regression test that reproduces the original race over 100,000 iterations is included.

✅ Checklist

  • I've added at least one test that validates that my change is working, if appropriate
  • I've followed the code style of the rest of the project
  • I've read the Contribution Guidelines
  • I've updated the documentation if necessary

@bok- bok- added bug Something isn't working patch A tiny change according to semver. labels May 8, 2026
bok- and others added 2 commits May 8, 2026 19:11
@bok- bok- force-pushed the fix/asynccurrentvalue-deadlock branch from 60e13cc to 8a7dd58 Compare May 8, 2026 09:20
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 8, 2026

@bok- bok- merged commit 3cfc3a8 into main May 8, 2026
37 checks passed
@bok- bok- deleted the fix/asynccurrentvalue-deadlock branch May 8, 2026 09:28
@gqbit
Copy link
Copy Markdown
Contributor

gqbit commented May 8, 2026

Beautiful - thank you @bok-!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working patch A tiny change according to semver.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lock-order inversion deadlock in AsyncCurrentValue when cancellation races an update

2 participants