posix-sync
Idiomatic Rust interface for POSIX synchronisation primitives.
Every primitive comes in two flavours:
- An owned variant, which allocates the underlying pthread object, destroys it on drop as long as nothing still holds it, and can be used entirely from safe code
- A borrowed variant, which points at memory you supply (e.g. a shared mapping),
is
Copy, never destroys anything, and whose methods areunsafebecause another process may invalidate the underlying object
use ;
let mtx = new
.with_type
.build_owned;
let guard = mtx.lock.unwrap;
drop;
Robustness is a type parameter rather than an attribute, so the guard type follows from it and the two kinds of lock cannot be mixed up. A robust mutex hands the next locker a guard that has to be matched on:
use ;
let mtx = new.build_owned;
match mtx.lock.unwrap
That block is marked ignore because Robust only exists on the platforms in the table
below. The mutex module docs
carry the same example against a shared mapping, compiled wherever it applies.
Modules
| Module | Owned | Borrowed | Notes |
|---|---|---|---|
mutex |
OwnedMutex<R> |
BorrowedMutex<'a, R> |
robustness, type, protocol, priority ceiling, timed locking |
condvar |
OwnedCondvar |
BorrowedCondvar<'a> |
selectable clock for timed waits |
rwlock |
OwnedRwLock |
BorrowedRwLock<'a> |
reader/writer preference on glibc, timed locking |
All three can be process-shared, as long as the platform supports it (see the table
below). They are non-poisoning, and therefore !UnwindSafe and !RefUnwindSafe.
Platform support
| Linux (glibc) | Linux (musl) | FreeBSD | DragonFly | NetBSD | OpenBSD | macOS/iOS | Android | |
|---|---|---|---|---|---|---|---|---|
| Process sharing | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ |
| Robust mutexes | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Timed mutex locking | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Timed rwlock locking | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Condvar clock selection | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Priority inheritance | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| Priority ceilings | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Reader/writer preference | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
- Process sharing:
with_sharingand the*Sharingenums on all three builders. DragonFly, NetBSD and OpenBSD never implemented the option: OpenBSD's libraries export no pshared functions for mutexes or condvars at all, NetBSD's returnENOSYSfor the shared value, and DragonFly's reject it withEINVAL. Where the row is ❌,with_sharingand the*Sharingenums do not exist, so the locks there can only synchronise threads within a single process, never two processes over shared memory. - Robust mutexes: macOS/iOS, NetBSD, OpenBSD and Android do not implement robust mutexes at all. DragonFly declares the robust functions but does not define them.
- Timed mutex locking: macOS/iOS has no
pthread_mutex_timedlock. - Timed rwlock locking: macOS/iOS never implemented the timed rwlock functions.
- Condvar clock selection: macOS/iOS has no
pthread_condattr_setclock, so a condvar there always measures its timed waits againstCLOCK_REALTIME. - Priority inheritance: NetBSD rejects
PTHREAD_PRIO_INHERITwithENOTSUPwhile accepting the other two protocols. On Android the protocol functions only exist from API level 28, so selecting any protocol there needs a target at least that new. - Priority ceilings: the musl and Android C libraries leave the POSIX Thread Priority
Protection option unimplemented: neither exports
pthread_mutexattr_setprioceiling, and both rejectPTHREAD_PRIO_PROTECT. - Reader/writer preference: choosing who wins when readers and writers contend is a
GNU extension (
pthread_rwlockattr_setkind_np) rather than part of POSIX. Android's C library exports a variant with its own differently numbered constants, and FreeBSD declares the functions without defining them, so this crate offers the preference on glibc alone.
The crate checks against Rust 1.65.
License
MIT. See LICENSE.