Skip to content

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_lot mostly 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. Returns None on 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_recursive lets 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::deadlock detector — 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_lot goes 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_lot is 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_for timeouts, read_recursive, deadlock detector). Also the canonical wiki instance of a parking_lot production bug reported to and fixed by upstream — PR #466.
Last updated · 200 distilled / 1,178 read