Fix subject deadlocks during concurrent cancellation - #59
Merged
Merged
Conversation
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #59 +/- ##
==========================================
- Coverage 95.41% 94.92% -0.49%
==========================================
Files 78 79 +1
Lines 7541 7767 +226
==========================================
+ Hits 7195 7373 +178
- Misses 346 394 +48 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Snapshot subscriber channels under the subject state lock, then deliver values and termination after releasing it. Keep current-value and replay state updates atomic with the snapshot. Cover all six subject variants with suspended-consumer cancellation races for value sends, finishes, and failures.
twittemb
force-pushed
the
codex/fix-subject-cancellation-deadlock
branch
from
October 3, 2026 08:44
806c2e5 to
a1b8658
Compare
3 of 5 tasks
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.
Description
When a subject sends a value or termination while a suspended consumer is cancelled, delivery can hold the subject state lock while continuation resumption waits for the task-status lock. The synchronous cancellation handler holds the task-status lock and waits for the subject lock in
unregister(), producing a deadlock. The buffered channels already resume outside their own locks; the enclosing subject lock is the problem.Apply the channel-snapshot solution from the issue analysis to all six subjects:
cancel()against value delivery, finish, and throwing failure. The six tests exercise 15,000 races and verify consumer exit, with bounded test timeouts.Closes #52.
Validation
Rebased without conflicts onto
mainat495d616, which includes merged #57. The new subscriber-registration implementation and all ten race regressions from #57 are retained unchanged.On an Apple Silicon Mac with Apple Swift 6.4:
cancel → unregister → subject lockandsubject.send → channel.send → continuation.resume → task-status lock.swift test --filter 'Async.*Subject.*Tests': 49 tests passed, including 100,000 subscription races from Fix race condition in subjects #57 and 15,000 cancellation races from this PR across all six subject variants.swift test --enable-code-coverage -Xswiftc -suppress-warnings: 148 tests passed on the confirmation run after rebasing.swift build -Xswiftc -suppress-warnings: passed.git diff --check: passed.The first full-suite run after rebasing hit the existing missing-value assertion in
AsyncMulticastSequenceTests.test_multiple_loops_uses_provided_stream([1, 1]instead of[1, 1, 1]). The same assertion also failed in an isolated checkout of the newly updated, untouchedmainat495d616. All subject tests passed in both full-suite runs. This separate multicast race remains outside the cancellation fix; the green confirmation run does not establish that the suite is free of flakiness.GitHub Actions attempt 1 for the rebased commit passed the build and all subject tests, but failed on the same multicast assertion reproduced on current
main. The single retry (attempt 2) passed the full test job, coverage generation, and upload. Both build and test checks are green for the rebased commita1b8658. No tests were skipped or assertions weakened.Compatibility and ordering
This PR builds on #57's atomic subscriber registration. Replay and immediate termination remain inside
handleNewConsumer's critical region: that channel is still private, has no awaiting consumer, and those operations cannot resume a continuation. Values and termination sent to already registered channels are delivered outside the subject lock, removing the deadlock while retaining the registration fix.The snapshot removes the subject-lock/task-status-lock inversion without introducing a second delivery lock. Concurrent sends can interleave their deliveries after taking their snapshots; callers needing strict order across producers must serialize those sends. Sequential sends remain synchronous and ordered.
Checklist