Expand description
A declared lock hierarchy for [PlayerController], and a tripwire that
enforces it.
The controller carries seventeen separate mutexes, reached from the MPV event
loop, JNI callbacks, sleep/autoplay timers, the session poller and every IPC
command. Nothing about that arrangement prevents two threads taking the same
two locks in opposite orders, which deadlocks the player outright — and this
subsystem has already produced one deadlock (a tokio MutexGuard held in a
match scrutinee, which stalled the AdvanceToNext arm).
Today the code is disciplined: acquisitions are scoped, and previous() for
instance explicitly drops the backend guard before touching the queue. But
that holds by convention, and convention is not checked. LOCK_ORDER
writes the convention down and every_overlapping_acquisition_respects_the_order
fails the build when a change breaks it.
Ordering only matters where one guard is still held while another lock is taken. Acquiring two locks one after another, each released before the next, cannot deadlock — so the analysis looks for overlap, not for mere sequence.
TRACES: UR-005 | DR-052
Structs§
- Overlap
- One lock acquired while another is still held.
Constants§
- LOCK_
ORDER - The order in which
PlayerController’s locks may be nested.
Functions§
- overlapping_
acquisitions - Find every place
srctakes a lock while holding another. - parse_
acquisition 🔒 - The first
self.other.lock_safe()onlinethat is notheld. - parse_
binding 🔒 let [mut] name = self.field.lock_safe()→(name, field).- rank
- Rank of
fieldinLOCK_ORDER, orNoneif it is not a declared lock.