Async lifecycle (MozPromise & shutdown) — dom/media review guidance
This covers the async-object lifetime idioms that are the most common source of media use-after-free and hangs.
General patterns
A
MozPromiseis resolved OR rejected exactly once, on every path. Check every early-return, error, and cancel path — a path that returns without settling the promise leaks/hangs the waiter; a path that can settle it twice is a bug.Thenruns on the intended thread. The resolve/reject callback is dispatched to the queue/thread the code assumes, and it only touches state that is valid on that thread.Request holders are tracked and disconnected. A pending
->Then(...)tracked by aMozPromiseRequestHolder(or aMozPromiseHolderon the producer side) must beDisconnect()/DisconnectIfExists()-ed during teardown, so a late resolution does not fire a callback into a destroyed object.No raw
thisin a promise callback. AThencallback (or lambda) that capturesthis/a raw pointer without holding a strongRefPtris a use-after-free the moment it resolves after the owner is gone. Either hold a strong ref or disconnect the request on teardown.Shutdown ordering. Nothing is dispatched or started after
Shutdown(); in-flight async work is completed or cancelled before the object tears down; a shutdown blocker is not satisfied until that teardown actually finishes.
dom/media specifics
Promise-chained pipeline. Decoders, demuxers, and the MDSM chain
MozPromises heavily (Init, Decode, Seek, Flush, Shutdown). A chain that can be abandoned mid-flight (seek/flush/error/shutdown) must disconnect its request holders so a stale resolution does not run against a reset or destroyed stage.MediaShutdownManager/ shutdown blockers. The MDSM/decoder registers a shutdown blocker; confirm the blocker is only released after the async teardown (flushing queues, shutting down the decoder, releasing the task queue) completes — not on a happy-path callback that may not run.Init vs Shutdown ordering. A pending Init/Decode promise that resolves after a Shutdown has begun must be handled (disconnected or made a no-op), not allowed to touch torn-down state.
Error paths settle the promise. On a decode/demux error, the corresponding promise is rejected (not dropped) so the state machine does not hang waiting.
One in-flight request per resource. Do not issue a new request for a resource (e.g.
RequestVideoData/RequestAudioDatafor a track) while a prior request for the same resource is still pending.Resolve waiting/retry promises on every transition. A “waiting for data” promise must be resolved on every transition to data-available (and any paired start-time state cleared with it); a missed resolution is a permanent stall, not just a delay.