SYSTEM Cited by 1 source
parking_lot (Rust lock crate)¶
parking_lot is Amanieu d'Antras's
Rust crate providing a replacement for the standard library's
synchronization primitives (Mutex, RwLock, Condvar, Once).
It's widely regarded in the Rust ecosystem as a drop-in upgrade:
faster, smaller in memory, and with a richer feature set.
Repo: github.com/Amanieu/parking_lot.
Crate: parking_lot.
Why people use it¶
Per Fly.io's 2025-05-28 deep-dive:
"People use
parking_lotmostly because it is very fast and tight (a lock takes up just a single 64-bit word). But we use it for the feature set." (Source: sources/2025-05-28-flyio-parking-lot-ffffffffffffffff)
The 64-bit-word compact lock representation is the defining
trick. For RwLock, that word is partitioned into 4 signaling
bits
(PARKED, WRITER_PARKED, WRITER, UPGRADEABLE) and a 60-bit
reader counter — all the state needed for the lock fits in one
atomically-updatable word.
Features the standard library doesn't have¶
try_write_for(Duration)/try_read_for(Duration)— bounded-wait lock acquisition. ReturnsNoneon timeout instead of blocking forever. Load-bearing for operators who need lock-contention to produce telemetry + failure-recovery paths rather than deadlock-looking hangs. See patterns/lock-timeout-for-contention-telemetry.read_recursive()— re-entrant read acquisition that sidesteps writer-preference starvation avoidance. If the current thread already holds a read lock,read_recursivelets it grab another one even when a writer is waiting. "A recursive read lock is an eldritch rite invoked when you need to grab a read lock deep in a call tree where you already grabbed that lock, but can't be arsed to structure the code properly to reflect that." See concepts/read-recursive-lock.parking_lot::deadlockdetector — optional feature. Runs on its own thread, tracks a waiting-for dependency graph, detects stalled threads. Notably does not detect artificial deadlocks where the lock word itself is corrupted and no thread actually owns it (per the 2025-05-28 case).- Compact lock word — 64 bits total (vs std's larger representation). Per-lock memory overhead is a single word.
Writer preference¶
parking_lot's RwLock prefers writers:
"
parking_lotgoes through some trouble to make sure a stampede of readers won't starve writers, who are usually outnumbered. It prefers writers by preventing readers from acquiring locks when there's at least one waiting writer." (Source: sources/2025-05-28-flyio-parking-lot-ffffffffffffffff)
This is what makes read_recursive meaningful: if a thread
already holds a read lock and tries to grab another read lock
via the standard read() API while a writer is waiting,
writer-preference blocks it and produces a self-deadlock.
read_recursive() exists specifically to bypass that.
The 2025-05-28 bug — bitwise double-free¶
From Fly.io's post: clearing bits atomically in the lock word used two's-complement addition of the inverse of the bits being cleared (a self-synchronizing atomic state update):
let state = self.state.fetch_add(
prev_value.wrapping_sub(WRITER_BIT | WRITER_PARKED_BIT),
Ordering::Relaxed,
);
This is equivalent to self.state & ~(WRITER|WRITER_PARKED)
only if the current state matches prev_value exactly. If
WRITER_PARKED was already cleared by another code path (a
reader-release that unparked the writer) and the timeout path
tries to clear it again, the subtraction doesn't cancel —
the counter wraps, the reader count saturates, and the lock
word becomes 0xFFFFFFFFFFFFFFFE. Canonical
concepts/bitwise-double-free instance. Patched in
PR #466
(issue #465).
Ptacek's framing is load-bearing for future users:
"The whole point of
parking_lotis that the locks are tiny, marshalled into a 64 bit word… you're reading a 3,000 word blog post about a single concurrency bug, so my guess is you're the kind of person who compulsively wants to understand how everything works. That's fine, but a word of advice: there are things where, if you find yourself learning about them in detail, something has gone wrong. One of those things is the precise mechanisms used by your RWLock implementation."
Seen in¶
- sources/2025-05-28-flyio-parking-lot-ffffffffffffffff —
Load-bearing architectural intro (64-bit word representation,
4 signaling bits + 60-bit counter, writer preference,
try_write_fortimeouts,read_recursive, deadlock detector). Also the canonical wiki instance of aparking_lotproduction bug reported to and fixed by upstream — PR #466.
Related¶
- systems/fly-proxy — Uses
parking_lotlocks for the Catalog; the Rust application that surfaced PR #466. - systems/tokio — Different runtime;
parking_lotlocks are synchronous. Tokio apps use them anyway. - concepts/bitwise-double-free — Class of bug upstream PR #466 fixes.
- concepts/lock-state-self-synchronizing — The optimisation that enables the bug class.
- concepts/read-recursive-lock — The
read_recursivefeature. - concepts/deadlock-vs-lock-contention — Why
try_write_foris a useful discrimination tool. - patterns/lock-timeout-for-contention-telemetry — What
try_write_forexists for. - patterns/read-recursive-as-desperation-probe — The
ad-hoc use of
read_recursivefor debugging. - patterns/upstream-the-fix —
parking_lotPR #466 as an instance. - companies/flyio — The user that reported + fixed the bug.