Repository navigation
A Drive that fails and rejoins inside one audio block keeps its new join request (#945) - #956
Merged
Merged
Conversation
…oin request (#945) The join block read the requests, acted on them, then cleared what it read. A stop and a reattach landing in between had their new request wiped, and the Copy was fed with no join frame. The block now claims the requests with one exchange, so a later request survives to the next block, and a Copy stopped or asked to join again since the claim is taken back out of capturing until that block serves it. Real-time path (ADR 0002): atomics only. Assisted-by: Claude Code:claude-opus-5-5
Skeyelab
enabled auto-merge (squash)
October 25, 2026 03:01
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
3 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.
Closes #945.
Real-time path (ADR 0002): human review of the diff. This changes the join block in
Capture.receive, which runs on the audio thread. Atomics only: no locks, no allocation, no blocking calls (checked by a Code Reviewer).The bug
The join block read
joinRequests, acted on it, then cleared what it read. AstopFeedingplusattachMidTakeof the same Copy landing in between had the new request wiped, and the Copy was fed with no join frame.The fix
exchange(0)instead of a load and a laterbitwiseAnd. A request posted after the claim survives to the next block. A block with nothing waiting still does only a plain read.capturingany claimed Copy that is stopped or has a fresh request pending. That Copy isn't fed on this block; the next block serves the fresh request at the right join frame.afterJoinRead(nil in the app) moved to after the join frames are set, before the Copies are added tocapturing, so the race is reachable.Tests
stopAndRejoinDuringJoinBlock: the Copy is stopped and attached again from inside the hook. Red first: before the fix,joinedAtwas nil and the ring held 960 frames. Now it isn't fed on that block, then joins at 960 with 480 frames.exchangeor the fresh-request take-out turns the new test red.VERIFY_QUICK=1 ./scripts/verify.shpassed (noApp/change).Still open, not in this PR
All very narrow. TakeSession starts a rejoin only after an async Drive prepare, so it isn't expected to produce these:
stopCapturinglanding between the claim and the OR intocapturingputs the claimed Copies back after Stop. One option:stopCapturingsets everystoppedFeedsbit.Device Take needed (before External testers)
Checked by tests only. Ship in the next
[internal]tag. Eric's Take from that TestFlight build: a Drive that fails as it joins mid-Take and is joined again, with the Drive's Stems in line with the Device's and no false dropped frames in the report.