xtc_sync(3)
---xtc_sync(3)
async synchronisation primitives
| XTC_SYNC(3) | Library Functions Manual | XTC_SYNC(3) |
NAME
xtc_amutex,
xtc_amutex_create,
xtc_amutex_create_ex,
xtc_amutex_static,
xtc_amutex_destroy,
xtc_amutex_lock,
xtc_amutex_try_lock,
xtc_amutex_unlock,
xtc_arwlock,
xtc_arwlock_create,
xtc_arwlock_destroy,
xtc_arwlock_rdlock,
xtc_arwlock_wrlock,
xtc_arwlock_unlock,
xtc_rwlock,
xtc_rwlock_create,
xtc_rwlock_destroy,
xtc_rwlock_rdlock,
xtc_rwlock_wrlock,
xtc_rwlock_unlock,
xtc_notify,
xtc_notify_create,
xtc_notify_destroy,
xtc_notify_signal,
xtc_notify_wait, xtc_sem,
xtc_sem_create,
xtc_sem_destroy,
xtc_sem_post,
xtc_sem_acquire,
xtc_sem_try_acquire,
xtc_sem_count, xtc_barrier,
xtc_barrier_create,
xtc_barrier_destroy,
xtc_barrier_wait, xtc_gate,
xtc_gate_create,
xtc_gate_destroy,
xtc_gate_enter,
xtc_gate_leave,
xtc_gate_close,
xtc_gate_drain,
xtc_gate_count,
xtc_abort_source,
xtc_abort_source_create,
xtc_abort_source_destroy,
xtc_abort_source_fire,
xtc_abort_source_token,
xtc_abort_token_is_aborted,
xtc_abort_token_reason —
async synchronisation primitives
SYNOPSIS
#include <xtc.h>
#include <xtc_sync.h>
int
xtc_amutex_create(xtc_amutex_t
**out);
int
xtc_amutex_create_ex(xtc_amutex_t
**out, unsigned
flags);
xtc_amutex_t *
xtc_amutex_static(unsigned
flags);
void
xtc_amutex_destroy(xtc_amutex_t
*m);
int
xtc_amutex_lock(xtc_amutex_t
*m, int64_t
timeout_ns);
int
xtc_amutex_try_lock(xtc_amutex_t
*m);
int
xtc_amutex_unlock(xtc_amutex_t
*m);
int
xtc_arwlock_create(xtc_arwlock_t
**out);
void
xtc_arwlock_destroy(xtc_arwlock_t
*rw);
int
xtc_arwlock_rdlock(xtc_arwlock_t
*rw, int64_t
timeout_ns);
int
xtc_arwlock_wrlock(xtc_arwlock_t
*rw, int64_t
timeout_ns);
int
xtc_arwlock_unlock(xtc_arwlock_t
*rw);
int
xtc_rwlock_create(xtc_rwlock_t
**out);
void
xtc_rwlock_destroy(xtc_rwlock_t
*rw);
int
xtc_rwlock_rdlock(xtc_rwlock_t
*rw, int64_t
timeout_ns);
int
xtc_rwlock_wrlock(xtc_rwlock_t
*rw, int64_t
timeout_ns);
int
xtc_rwlock_unlock(xtc_rwlock_t
*rw);
int
xtc_notify_create(xtc_notify_t
**out);
void
xtc_notify_destroy(xtc_notify_t
*n);
int
xtc_notify_signal(xtc_notify_t
*n);
int
xtc_notify_wait(xtc_notify_t
*n, int64_t
timeout_ns);
int
xtc_sem_create(unsigned
initial, xtc_sem_t
**out);
void
xtc_sem_destroy(xtc_sem_t
*s);
int
xtc_sem_post(xtc_sem_t
*s, unsigned
n);
int
xtc_sem_acquire(xtc_sem_t
*s, unsigned n,
int64_t timeout_ns);
int
xtc_sem_try_acquire(xtc_sem_t
*s, unsigned
n);
int
xtc_sem_count(const
xtc_sem_t *s);
int
xtc_barrier_create(unsigned
n, xtc_barrier_t
**out);
void
xtc_barrier_destroy(xtc_barrier_t
*b);
int
xtc_barrier_wait(xtc_barrier_t
*b);
int
xtc_gate_create(xtc_gate_t
**out);
void
xtc_gate_destroy(xtc_gate_t
*g);
int
xtc_gate_enter(xtc_gate_t
*g);
int
xtc_gate_leave(xtc_gate_t
*g);
int
xtc_gate_close(xtc_gate_t
*g);
int
xtc_gate_drain(xtc_gate_t
*g, int64_t
timeout_ns);
int
xtc_gate_count(const
xtc_gate_t *g);
int
xtc_abort_source_create(xtc_abort_source_t
**out);
void
xtc_abort_source_destroy(xtc_abort_source_t
*src);
int
xtc_abort_source_fire(xtc_abort_source_t
*src, int
reason);
int
xtc_abort_source_token(xtc_abort_source_t
*src, xtc_abort_token_t
*tok);
int
xtc_abort_token_is_aborted(const
xtc_abort_token_t *tok);
int
xtc_abort_token_reason(const
xtc_abort_token_t *tok);
DESCRIPTION
xtc_sync provides async-aware
synchronisation primitives that integrate with xtc_loop(3)
scheduling: blocked acquires park the calling fiber rather than blocking the
OS thread.
- xtc_amutex
- Async mutex. Blocked acquires park the fiber. Use for critical sections
held across xtc_recv(3) or other async I/O. Compare with
xtc_lwlock(3) which uses pthread mutex underneath
(blocks the OS thread).
xtc_amutex_create() allocates a mutex;xtc_amutex_create_ex() takes a flags word;xtc_amutex_static() returns a process-static instance.xtc_amutex_lock() parks until acquired or the timeout_ns deadline elapses;xtc_amutex_try_lock() never parks;xtc_amutex_unlock() releases; andxtc_amutex_destroy() frees it. A proc that exits while holding an amutex leaves it held forever (there is no robust-mutex recovery, and a later proc never inherits a recursive amutex's ownership), so release it in anxtc_proc_at_exit() hook (see xtc_proc(3)) if the proc can die inside the critical section. - xtc_arwlock
- Async reader-writer latch (shared / exclusive). Blocked acquires park the
fiber, exactly as xtc_amutex, so a holder may park
on I/O while latched and lock coupling may hold a parent latch across a
child fix without wedging a cooperative loop. FIFO fairness keeps a read
stream from starving a waiting writer. This is the reader-writer primitive
a concurrent B-tree latches its pages with.
xtc_arwlock_create() andxtc_arwlock_destroy() manage the object;xtc_arwlock_rdlock() andxtc_arwlock_wrlock() take it shared or exclusive with a timeout_ns deadline;xtc_arwlock_unlock() releases the current hold. - xtc_rwlock
- Reader-writer lock with writer priority, built on a pthread mutex and
condition variable: a blocked acquire blocks the OS thread (it does NOT
park the fiber). Use xtc_arwlock instead on the hot
path of an event loop.
xtc_rwlock_create(),xtc_rwlock_destroy(),xtc_rwlock_rdlock(),xtc_rwlock_wrlock(), andxtc_rwlock_unlock() mirror the async variant. - xtc_notify
- A 0-or-1 latch.
xtc_notify_create() andxtc_notify_destroy() manage the object. Producersxtc_notify_signal(); consumersxtc_notify_wait() until signalled. Each signal is handed to exactly one waiting fiber, oldest first; with no fiber waiting it is stored (and wakes any OS-thread waiter), and signals that arrive before the next wait collapse into one. Useful for one-shot ready signals. - xtc_sem
- Counting semaphore.
xtc_sem_create() takes an initial count;xtc_sem_destroy() frees it.xtc_sem_post() adds n permits;xtc_sem_acquire() takes n permits, parking until available or the timeout_ns deadline. A post wakes the parked fibers the new count can satisfy, oldest first, not every waiter; a waiter stays queued until it takes its permits, times out or is killed, so no post is lost. Admission is not strictly FIFO: a caller that finds enough permits takes them without queueing;xtc_sem_try_acquire() never parks; andxtc_sem_count() reports the current permit count. - xtc_barrier
- Synchronisation point: n participants created by
xtc_barrier_create() callxtc_barrier_wait() until all have arrived; then all proceed.xtc_barrier_destroy() frees it. - xtc_gate
- A counting gate.
xtc_gate_create() andxtc_gate_destroy() manage the object.xtc_gate_enter() andxtc_gate_leave() bracket in-flight work;xtc_gate_close() rejects new entrants;xtc_gate_drain() parks until the in-flight count reaches zero or the timeout_ns deadline, whether or not the gate is closed; andxtc_gate_count() reports the number of active occupants. - xtc_abort_source
- Cancellation token.
xtc_abort_source_create() andxtc_abort_source_destroy() manage the source. Initiator callsxtc_abort_source_fire() with a reason to signal cancellation;xtc_abort_source_token() hands out a token participants poll withxtc_abort_token_is_aborted() andxtc_abort_token_reason(). Used to wire timeout / shutdown into long-running operations cooperatively.
All primitives are thread-safe. A blocked acquire from a fiber parks the fiber on the primitive's own wait queue, so the OS thread is free to run other work; a caller that is not on a loop blocks on a condition variable.
A timed acquire that is granted before its deadline
cancels its deadline timer, so a later plain
xtc_yield()
of the same fiber does not wait for the old deadline.
Cancellation
A proc killed with
xtc_exit_pid()
while parked in
xtc_notify_wait(),
xtc_sem_acquire(),
xtc_amutex_lock(),
xtc_arwlock_rdlock(),
xtc_arwlock_wrlock(),
xtc_barrier_wait()
or
xtc_gate_drain()
leaves the wait cleanly before it unwinds: it is removed from the wait
queue, a lock, signal or permit already handed to it is passed on to the
next waiter, and its deadline timer is cancelled. The call does not return.
A killed barrier party still counts as arrived for the current generation.
Inside an
xtc_uncancelable()
region the kill is deferred and the wait continues. The kill is noticed when
the parked proc next runs (a wake, its own deadline, or the kill itself when
the proc layer wakes parked targets).
xtc_rwlock is not covered: it blocks the OS thread and cannot be interrupted.
CHOOSING
- For database-style transactional locking with deadlock detection: xtc_lockmgr(3).
- For short critical sections inside one xtc_loop: xtc_lwlock(3).
- For read-mostly state with wait-free readers: xtc_lrlock(3) or xtc_rcu(3).
- For "wait until N producers have all signalled": xtc_barrier or xtc_sem.
- For cancellation propagation: xtc_abort_source.
SEE ALSO
xtc_async(3), xtc_proc(3), xtc_lwlock(3), xtc_lrlock(3), xtc_lockmgr(3), xtc_rcu(3), xtc(7)
HISTORY
Appeared in xtc 0.1.
| May 28, 2026 | Debian |