Name Description Size
mod.rs Instrumented lock types. This module defines a set of instrumented wrappers for the lock types used in `wgpu-core` ([`Mutex`], [`RwLock`], and [`SnatchLock`]) that help us understand and validate `wgpu-core` synchronization. - The [`ranked`] module defines lock types that perform run-time checks to ensure that each thread acquires locks only in a specific order, to prevent deadlocks. - The [`vanilla`] module defines lock types that are uninstrumented, no-overhead wrappers around the standard lock types. (We plan to add more wrappers in the future.) If the `wgpu_validate_locks` config is set (for example, with `RUSTFLAGS='--cfg wgpu_validate_locks'`), `wgpu-core` uses the [`ranked`] module's locks. We hope to make this the default for debug builds soon. Otherwise, `wgpu-core` uses the [`vanilla`] module's locks. [`Mutex`]: parking_lot::Mutex [`RwLock`]: parking_lot::RwLock [`SnatchLock`]: crate::snatch::SnatchLock 1416
rank.rs Ranks for `wgpu-core` locks, restricting acquisition order. See [`LockRank`]. 7052
ranked.rs Lock types that enforce well-ranked lock acquisition order. This module's [`Mutex`] and [`RwLock` types are instrumented to check that `wgpu-core` acquires locks according to their rank, to prevent deadlocks. To use it, put `--cfg wgpu_validate_locks` in `RUSTFLAGS`. The [`LockRank`] constants in the [`lock::rank`] module describe edges in a directed graph of lock acquisitions: each lock's rank says, if this is the most recently acquired lock that you are still holding, then these are the locks you are allowed to acquire next. As long as this graph doesn't have cycles, any number of threads can acquire locks along paths through the graph without deadlock: - Assume that if a thread is holding a lock, then it will either release it, or block trying to acquire another one. No thread just sits on its locks forever for unrelated reasons. If it did, then that would be a source of deadlock "outside the system" that we can't do anything about. - This module asserts that threads acquire and release locks in a stack-like order: a lock is dropped only when it is the *most recently acquired* lock *still held* - call this the "youngest" lock. This stack-like ordering isn't a Rust requirement; Rust lets you drop guards in any order you like. This is a restriction we impose. - Consider the directed graph whose nodes are locks, and whose edges go from each lock to its permitted followers, the locks in its [`LockRank::followers`] set. The definition of the [`lock::rank`] module's [`LockRank`] constants ensures that this graph has no cycles, including trivial cycles from a node to itself. - This module then asserts that each thread attempts to acquire a lock only if it is among its youngest lock's permitted followers. Thus, as a thread acquires locks, it must be traversing a path through the graph along its edges. - Because there are no cycles in the graph, whenever one thread is blocked waiting to acquire a lock, that lock must be held by a different thread: if you were allowed to acquire a lock you already hold, that would be a cycle in the graph. - Furthermore, because the graph has no cycles, as we work our way from each thread to the thread it is blocked waiting for, we must eventually reach an end point: there must be some thread that is able to acquire its next lock, or that is about to release a lock. Thus, the system as a whole is always able to make progress: it is free of deadlocks. Note that this validation only monitors each thread's behavior in isolation: there's only thread-local state, nothing communicated between threads. So we don't detect deadlocks, per se, only the potential to cause deadlocks. This means that the validation is conservative, but more reproducible, since it's not dependent on any particular interleaving of execution. [`lock::rank`]: crate::lock::rank 12533
vanilla.rs Plain, uninstrumented wrappers around [`parking_lot`] lock types. These definitions are used when no particular lock instrumentation Cargo feature is selected. 3406