Reclaim FFmpeg sessions after late worker exit - #140
Blackspirits wants to merge 1 commit into
Conversation
Blackspirits
left a comment
There was a problem hiding this comment.
Final adversarial review on 4edde2ba42d0e81ce3d1504818eb13a3e7af606f after CI SubtitleEdit#279: no blocker found. Verified worker accounting is rolled back on Thread.Start failure, deferred cleanup is one-shot, the last worker never blocks on _lifecycleLock, the timeout/last-exit race is closed by the immediate readiness check, and a later explicit Dispose can still win cleanup safely. Permanently stuck workers remain retained rather than freed unsafely. No merge/promotion performed.
Blackspirits
left a comment
There was a problem hiding this comment.
Final adversarial review on 4edde2ba42d0e81ce3d1504818eb13a3e7af606f after CI SubtitleEdit#279: no blocker found. Verified the worker counter is balanced across successful/failed Thread.Start, workers never take the lifecycle lock while being joined, deferred cleanup is one-shot and rechecks zero active workers under the lifecycle lock, a later explicit Dispose may win safely, and permanently stuck workers remain fail-closed retained resources. No merge/promotion performed.
Purpose
Dependent teardown-lifetime follow-up to #139 ("Fence stale FFmpeg session owner publication").
#115 correctly fails closed when a Session worker does not stop within the teardown timeout, retaining every worker-visible resource instead of risking use-after-free. #139 fences any worker that survives that timeout from publishing owner state into a newer load. One lifecycle gap remained: once CloseFile removes the Session from the owner, no later caller necessarily retains a path to retry Dispose, so a worker that exits shortly after the timeout can leave the retained native/session resources leaked for the rest of the process.
Current upstream
SubtitleEdit/subtitleeditmain was rechecked atd6917286e355976da953d0ee22208b4bf9461699; its latest change is unrelated and no open upstream PR was found for this teardown-reclamation boundary.Finding fixed
#115 made Session.Dispose retry-safe internally, but
FfmpegPlayer.CloseFile()exchanges_sessionto null before calling it.If a worker misses the join timeout:
That turns a temporary teardown timeout into a permanent controlled leak.
Fix
Session now owns worker-exit accounting and one-shot deferred reclamation:
StartWorker();finally, after its loop/local codec cleanup has completed;No global retired-session collection, polling loop or permanently blocked reaper thread is introduced.
Regression coverage
Pure tests pin the deferred-cleanup gate:
Existing #139 stale-publication tests remain unchanged and continue to fence the old Session until it exits.
Scope / branch state
088211bde3024739667ef55448b483064c14cb904edde2ba42d0e81ce3d1504818eb13a3e7af606fd6917286e355976da953d0ee22208b4bf9461699AI assistance: ChatGPT was used for adversarial timeout/reclamation review, worker-lifetime accounting, lock-order analysis, exact-once cleanup modelling and focused regression design.
Final CI
Authoritative run: SubtitleEdit#279 on
4edde2ba42d0e81ce3d1504818eb13a3e7af606fFinal adversarial review was performed on this exact HEAD after CI; no blocker found.