xtc_lwlock(3)

---

xtc_lwlock(3)

lightweight lock with shared / exclusive modes

XTC_LWLOCK(3) Library Functions Manual XTC_LWLOCK(3)

xtc_lwlock_init, xtc_lwlock_destroy, xtc_lwlock_acquire, xtc_lwlock_acquire_cond, xtc_lwlock_release, xtc_lwlock_held_by_me, xtc_lwlock_held_by_me_in_mode, xtc_lwlock_track_enable, xtc_lwlock_track_violations, xtc_lwlock_track_reset, xtc_lwlock_track_set_handlerlightweight lock with shared / exclusive modes

#include <xtc.h>
#include <xtc_lwlock.h>

int
xtc_lwlock_init(xtc_lwlock_t *lock, uint16_t tranche);

void
xtc_lwlock_destroy(xtc_lwlock_t *lock);

int
xtc_lwlock_acquire(xtc_lwlock_t *lock, xtc_lwlock_mode_t mode);

int
xtc_lwlock_acquire_cond(xtc_lwlock_t *lock, xtc_lwlock_mode_t mode);

void
xtc_lwlock_release(xtc_lwlock_t *lock);

int
xtc_lwlock_held_by_me(const xtc_lwlock_t *lock);

int
xtc_lwlock_held_by_me_in_mode(const xtc_lwlock_t *lock, xtc_lwlock_mode_t mode);

void
xtc_lwlock_track_enable(int on);

long
xtc_lwlock_track_violations(void);

void
xtc_lwlock_track_reset(void);

void
xtc_lwlock_track_set_handler(xtc_lwlock_track_fn fn, void *user);

xtc_lwlock is a lightweight lock with shared (reader) and exclusive (writer) modes. Single atomic on the fast path; pthread_mutex / cond on the contended path. Ported from PostgreSQL's src/backend/storage/lmgr/lwlock.c.

The optional lock-order (WITNESS) tracker is off by default. () turns it on (and off); while on, each acquire records the order “tranche A was held when tranche B was acquired”, keyed by the lock's tranche, and an acquisition that reverses a previously-seen order is a lock-order inversion -- the precursor of a two-lock deadlock the lwlock primitive cannot otherwise detect. () returns the running count; () registers a callback fired with (held_tranche, acquired_tranche) on each inversion; and () clears the edge set and counter. The tracker has overhead and is intended for test and staging builds, not production hot paths.

The lock state is encoded in one _Atomic uint32_t: the high three bits hold the LW_FLAG_HAS_WAITERS, LW_FLAG_WAKE_IN_PROGRESS, and LW_FLAG_QUEUE_LOCKED flags; the low bits hold either the shared-holder count or the LW_VAL_EXCLUSIVE sentinel. An uncontended acquire is one CAS.

() initialises the lock in place. tranche is a user tag for diagnostics (groups locks by purpose so profilers can attribute contention).

() blocks until the calling thread holds the lock in mode:

Multiple threads can hold the lock concurrently in shared mode. Excluded by an exclusive holder.
Only one thread holds the lock; excludes all readers.

() is the non-blocking variant: returns XTC_OK if the acquire succeeded immediately, XTC_E_AGAIN otherwise.

() drops the lock in whichever mode the calling thread acquired it. The mode is tracked in a per-thread held-list so the caller does not need to pass it back.

() returns 1 if the calling thread currently holds lock in any mode, 0 otherwise. Useful in assertions and in code that needs to call a function that might or might not already hold a particular lock.

() narrows that test to a specific mode: it returns 1 only if the calling thread holds lock in exactly that mode.

xtc ships several locks; pick by workload:

xtc_lwlock
General-purpose reader/writer. Best for short critical sections with mixed reader/writer ratio. This page.
xtc_lrlock
Wait-free reads via two-copy publish. Best for read-heavy workloads (read:write ratio > 50:1) where reads must never block. See xtc_lrlock(3).
xtc_lockmgr
Transactional locking with deadlock detection, multiple modes, victim selection. Best for database-style workloads with named lockable objects. See xtc_lockmgr(3).
xtc_amutex
Async-aware mutex; integrates with the loop scheduler. Use for critical sections that span async I/O. See xtc_sync(3).

xtc_lwlock_init(), xtc_lwlock_acquire(), and xtc_lwlock_acquire_cond() return XTC_OK on success or a negative XTC_E_* code.

xtc_lwlock_t lk;
xtc_lwlock_init(&lk, /* tranche */ 1);

/* hot path: reader */
xtc_lwlock_acquire(&lk, XTC_LW_SHARED);
read_state();
xtc_lwlock_release(&lk);

/* mutator */
xtc_lwlock_acquire(&lk, XTC_LW_EXCLUSIVE);
update_state();
xtc_lwlock_release(&lk);

xtc_lwlock_destroy(&lk);

xtc_lrlock(3), xtc_lockmgr(3), xtc_sync(3), xtc(7)

Ported from PostgreSQL's lrlck branch. Appeared in xtc 0.1.

May 28, 2026 Debian

View the mdoc source