posix_sync/lib.rs
1//! Rust bindings to the POSIX synchronisation primitives: mutexes, condition variables and
2//! reader/writer locks, with their attributes and RAII guards.
3//!
4//! A lock can be placed at an address you choose.
5//! This is useful for embedding synchronisation primitives into mapped memory.
6//! Some use cases, which aren't handled by `std::sync::Mutex`, include:
7//!
8//! - **Shared memory.** Two processes mapping the same region need the lock to live inside it.
9//! - **A holder that dies.** A robust mutex hands the next locker `EOWNERDEAD`, so it can repair
10//! the state.
11//! - **Real-time scheduling.** Priority inheritance and priority ceilings bound how long a
12//! low-priority holder can stall a high-priority waiter.
13//! - **Portability.** Process-shared locks are specified by POSIX rather than by any one kernel,
14//! so one implementation covers every platform that provides them. The alternative is a futex or
15//! another OS-specific primitive, rewritten per target.
16//! - **Relocking.** Error-checking and recursive types make a second lock on the same thread
17//! report a deadlock or succeed.
18//!
19//! Each primitive comes in two flavours:
20//!
21//! - An *owned* variant, which allocates its own pthread object, destroys it on drop as long as
22//! nothing still holds it, and can be used entirely from safe code.
23//! - A *borrowed* variant, which points at memory you supply, is `Copy`, destroys nothing
24//! implicitly, and has `unsafe` methods.
25//!
26//! | Module | Owned | Borrowed | Attributes |
27//! |--------|-------|----------|------------|
28//! | [`mutex`] | [`OwnedMutex`](mutex::OwnedMutex) | [`BorrowedMutex`](mutex::BorrowedMutex) | sharing, robustness, type, protocol, priority ceiling |
29//! | [`condvar`] | [`OwnedCondvar`](condvar::OwnedCondvar) | [`BorrowedCondvar`](condvar::BorrowedCondvar) | sharing, clock |
30//! | [`rwlock`] | [`OwnedRwLock`](rwlock::OwnedRwLock) | [`BorrowedRwLock`](rwlock::BorrowedRwLock) | sharing, reader/writer preference |
31//!
32//! All three can be process-shared, as long as the platform supports it (see the table below).
33//! There is no
34//! [poisoning](https://doc.rust-lang.org/std/sync/poison/struct.Mutex.html#poisoning), which
35//! makes them `!UnwindSafe` and `!RefUnwindSafe`.
36//!
37//! # Platform support
38//!
39//! | | Linux (glibc) | Linux (musl) | FreeBSD | DragonFly | NetBSD | OpenBSD | macOS/iOS | Android |
40//! |---|---|---|---|---|---|---|---|---|
41//! | Process sharing | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ |
42//! | Robust mutexes | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
43//! | Timed mutex locking | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
44//! | Timed rwlock locking | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
45//! | Condvar clock selection | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
46//! | Priority inheritance | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
47//! | Priority ceilings | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
48//! | Reader/writer preference | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
49//!
50//! - **Process sharing.** `with_sharing` and the `*Sharing` enums on all three builders.
51//! DragonFly, NetBSD and OpenBSD never implemented the option: OpenBSD's libraries export no
52//! pshared functions for mutexes or condvars at all, NetBSD's return `ENOSYS` for the shared
53//! value, and DragonFly's reject it with `EINVAL`. Where the row is ❌, `with_sharing` and the
54//! `*Sharing` enums do not exist, so the locks there can only synchronise threads within a
55//! single process, never two processes over shared memory.
56//! - **Robust mutexes.** macOS/iOS, NetBSD, OpenBSD and Android do not implement robust mutexes
57//! at all. DragonFly declares the robust functions but does not define them.
58//! - **Timed mutex locking.** macOS/iOS has no `pthread_mutex_timedlock`.
59//! - **Timed rwlock locking.** macOS/iOS never implemented the timed rwlock functions.
60//! - **Condvar clock selection.** macOS/iOS has no `pthread_condattr_setclock`, so a condvar
61//! there always measures its timed waits against `CLOCK_REALTIME`.
62//! - **Priority inheritance.** NetBSD rejects `PTHREAD_PRIO_INHERIT` with `ENOTSUP` while
63//! accepting the other two protocols. On Android the protocol functions only exist from API
64//! level 28, so selecting any protocol there needs a target at least that new.
65//! - **Priority ceilings.** The musl and Android C libraries leave the POSIX Thread Priority
66//! Protection option unimplemented: neither exports `pthread_mutexattr_setprioceiling`, and
67//! both reject `PTHREAD_PRIO_PROTECT`.
68//! - **Reader/writer preference.** Choosing who wins when readers and writers contend is a GNU
69//! extension (`pthread_rwlockattr_setkind_np`) rather than part of POSIX. Android's C library
70//! exports a variant with its own differently numbered constants, and FreeBSD declares the
71//! functions without defining them, so this crate offers the preference on glibc alone.
72
73#![cfg_attr(docsrs, feature(doc_cfg))]
74#![warn(missing_docs)]
75#![warn(rustdoc::all)]
76
77pub(crate) mod ffi;
78pub(crate) mod utils;
79
80pub mod condvar;
81pub mod mutex;
82pub mod rwlock;
83
84/// Compiles the code blocks in the README, so that the front page cannot drift from the API
85/// it advertises. `cfg(doctest)` holds only while rustdoc is collecting doctests, so this is
86/// invisible to every other build.
87#[cfg(doctest)]
88#[doc = include_str!("../README.md")]
89struct ReadmeDoctests;