Skip to content

Note idle for a stale start that lands mid-acknowledgement wait - #212

Merged
kahrendt merged 1 commit into
mainfrom
chrisuthe/task/split-pr-211-into-synctask-fix-winsock-init-and
Oct 28, 2026
Merged

kahrendt merged 1 commit into
mainfrom
chrisuthe/task/split-pr-211-into-synctask-fix-winsock-init-and

Conversation

@chrisuthe

Copy link
Copy Markdown
Member

SyncTask::wait_for_start_acknowledgement() could erase a stale start acknowledgement without noting idle for it, leaving the main loop's parked STREAM_END waiting forever.

Summary

  • The race. The loop read flags once at the top, then cleared COMMAND_START and decided whether an acknowledgement had arrived from that earlier snapshot. A stale acknowledgement (the start of a stream whose end overtook it) landing between the read and the clear was cleared but never seen, so the sync task skipped the note_sync_idle() the main loop's held STREAM_END waits for. Playback then deadlocked.
  • The fix. Decide from the bits event_flags_.clear() returns. EventFlags::clear() returns the pre-clear bits on both platforms, so whatever the clear took is what gets judged.

Notes

  • Not platform-specific. It showed up as a rare CI hang of ClientLifecycle.StreamEventsDrainedTogetherStartEachStreamOnItsOwnStart, and was split out of Fix what running on Windows turns up #211.
  • No new test. The window sits between two statements inside one function, and a deterministic test would need a hook in production code to stop between them, which the test standards rule out. The existing lifecycle test covers the behaviour; the reproduction below shows it catches the race once the window is widened.
  • docs/internals.md "Stream End and Start" already describes the intended behaviour (a stale acknowledgement notes idle), so it is unchanged.

Testing

  • Reproduced by adding a 2 ms sleep before the clear: without the fix the lifecycle test hung 3/3 runs; with the fix it passed 20/20 with the sleep in place (and 40/40 earlier, in Fix what running on Windows turns up #211).
  • Linux, GCC 16: host build clean; sendspin_tests 705/705. The ASan/UBSan build could not link on this machine (no sanitizer runtime installed), so the sanitizer and TSan runs are this PR's CI.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the change addressing the audio playback startup race.

No open issues 🎉

What changed in this PR

Fixes a race in audio playback startup where a stale start acknowledgement could be cleared without notifying the main loop that the sync task is idle, leaving a pending STREAM_END blocked indefinitely.

Changes:

  • Uses the pre-clear bits returned by EventFlags::clear() to detect start acknowledgements.
  • Updates the inline comment to explain why the earlier flag snapshot is insufficient.
File Description
src/​sync_task.cpp Detects acknowledgements arriving between the flag read and clear so stale starts receive the required idle notification.

Review effort: Balanced

@kahrendt kahrendt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kahrendt
kahrendt merged commit 76c50df into main Oct 28, 2026
17 checks passed
@kahrendt
kahrendt deleted the chrisuthe/task/split-pr-211-into-synctask-fix-winsock-init-and branch October 28, 2026 11:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants