Skip to content

Defer FFmpeg resource cleanup when a worker misses the stop timeout - #100

Draft
Blackspirits wants to merge 1 commit into
fix/ffmpeg-io-interrupt-c77cfrom
fix/ffmpeg-deferred-timeout-cleanup-c77c
Draft

Defer FFmpeg resource cleanup when a worker misses the stop timeout#100
Blackspirits wants to merge 1 commit into
fix/ffmpeg-io-interrupt-c77cfrom
fix/ffmpeg-deferred-timeout-cleanup-c77c

Conversation

@Blackspirits

@Blackspirits Blackspirits commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Summary

Even with #99's FFmpeg interrupt callback, Session.Dispose still had a dangerous fallback: each worker gets a bounded join, but after a timeout the code immediately disposes the audio sink, wait handles, AVFormatContext, and callback state anyway.

If a protocol, driver, or native call ignores/delays the interrupt callback, a timed-out worker can therefore continue running against resources that have already been released.

This change, layered on #99:

  • makes Session.Dispose idempotent;
  • keeps the existing bounded join so close/replacement does not block the UI indefinitely;
  • releases native/managed shared resources synchronously only when every worker has stopped;
  • if any worker misses the timeout (or Dispose is ever called from a worker), schedules final cleanup on a background task;
  • that task waits without a timeout for all workers to actually exit, then disposes the sink/events/format context and finally releases the interrupt GCHandle.

The failure mode is deliberately changed from possible use-after-free to temporary resource retention if native I/O refuses to terminate.

Validation

  • based on Interrupt blocked FFmpeg I/O when a load is closed or replaced #99 HEAD 1e442fe91711253ba3e843bdf2f1e5bc4730e4f6
  • diff is limited to Session teardown
  • constructor-failure paths with no started workers still clean up synchronously
  • full solution restore passed
  • full solution build passed
  • full solution test suite passed on the first run
  • UI suite: 5,151 passed, 9 skipped, 0 failed (5,160 total)
  • retry step was not used
  • validation run: #34780310800

AI assistance: ChatGPT was used to adversarially review FFmpeg worker/resource lifetime after bounded thread joins.

@Blackspirits Blackspirits left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Independent adversarial re-check: Session.Dispose is now idempotent; resources are released synchronously only after every worker has stopped. If any worker misses the bounded join (or Dispose is called from a worker), cleanup is deferred to a background task that retains the Session, joins all workers to completion, then disposes the sink/events/AVFormatContext and only afterward releases the interrupt GCHandle. This removes the previous use-after-free window at the cost of bounded resource retention if native I/O refuses to stop. Full CI #34780310800 passed restore, build and the complete suite on the first run; UITests reported 5,151 passed, 9 skipped, 0 failed. Retry was not used. A separate stale-frame publication guard is being validated because deferred workers can still finish a present iteration after close. Keep draft; no merge performed.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant