Expand description
Rust wrappers around POSIX mutexes.
This module exposes two kinds of mutexes: OwnedMutex and BorrowedMutex.
Both wrap an underlying libc::pthread_mutex_t, the mutex object POSIX defines, but differ
in the following ways:
OwnedMutex | BorrowedMutex | |
|---|---|---|
Implements Copy? | No | Yes |
| Destroys underlying mutex on drop? | When unlocked | Never |
| Can be used for shared memory IPC? | No | Yes |
Can be used without unsafe? | Yes | No |
Neither poisons, which makes them !UnwindSafe and !RefUnwindSafe. Shared memory IPC
additionally needs the mutex to be built with with_sharing(MutexSharing::Shared), an
option not every platform implements: see Platform support.
Both kinds are generic over a robustness marker, which decides what
happens when the owner of a lock dies without unlocking it. The robustness marker Standard
leaves everyone else blocked forever. The marker Robust hands the next owner an
indeterminate guard instead, giving the new owner the opportunity to repair whatever
the dead one left behind.
In POSIX terms, the markers are the two values the robustness attribute can take, both set
through pthread_mutexattr_setrobust: Standard corresponds to PTHREAD_MUTEX_STALLED, the
default, and Robust to PTHREAD_MUTEX_ROBUST.
Mutexes are constructed with MutexBuilder:
use posix_sync::mutex::{MutexBuilder, MutexType, robustness_markers::Standard};
let mtx = MutexBuilder::<Standard>::new()
.with_type(MutexType::ErrorCheck)
.build_owned();
let guard = mtx.lock()?;
// ... critical section ...
drop(guard);The next example puts a robust, process-shared mutex at some memory mapped region with
build_borrowed. We use the
memmap2 crate to create the mapping, though any
RAII wrapper would work.
use posix_sync::mutex::{
MutexBuilder, MutexSharing, RawMutexAlloc,
guards::RobustGuardContainer,
robustness_markers::Robust,
};
// A shared, page-aligned mapping that another process could map as well.
let file = tempfile::tempfile()?;
file.set_len(RawMutexAlloc::SIZE as u64)?;
let map = memmap2::MmapRaw::map_raw(&file)?;
let mtx = unsafe {
MutexBuilder::<Robust>::new()
.with_sharing(MutexSharing::Shared)
.build_borrowed(map.as_mut_ptr() as *mut RawMutexAlloc, &map)
};
match unsafe { mtx.lock()? } {
RobustGuardContainer::Standard(_guard) => {
// ... critical section ...
}
RobustGuardContainer::Indeterminate(guard) => {
// The last owner died holding the lock. Repair whatever it was protecting, and only
// then say so: until somebody does, every later lock fails with NotRecoverable.
let _guard = guard.make_consistent()?;
}
}
unsafe { mtx.destroy() };If the mutex was initialised by another process, use BorrowedMutex::from_raw instead of
the builder:
use posix_sync::mutex::{BorrowedMutex, RawMutexAlloc, robustness_markers::Standard};
// A mapping of the file in which another process already initialised a mutex.
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.open("mutex.shared")?;
let map = memmap2::MmapRaw::map_raw(&file)?;
// The marker has to match the robustness the initialising process picked; assume it picked
// Standard.
let mtx: BorrowedMutex<Standard> = unsafe {
BorrowedMutex::from_raw(map.as_mut_ptr() as *mut RawMutexAlloc, &map)
};
drop(unsafe { mtx.lock()? });When you are setting up a shared mapping that carries some state, the mutex guarding that
state, and perhaps a condvar to wait on it with, RawMutexAlloc::SIZE bytes need to be
reserved for the mutex, at an offset aligned to RawMutexAlloc::ALIGN.
§Platform support
Process sharing, robust mutexes, timed locking, the Inherit protocol and priority ceilings
are not available everywhere. See the table at the crate root.
Re-exports§
pub use builders::MutexBuilder;pub use builders::MutexProtocol;pub use builders::MutexType;pub use builders::MutexSharing;Neither DragonFly BSD nor NetBSD nor OpenBSD
Modules§
- builders
- This module contains
MutexBuilderalong with the various types used in its methods. - guards
- RAII guards returned from successful lock operations.
- robustness_
markers - Marker types used to select the robustness attribute of the mutex.
Structs§
- Borrowed
Mutex - A mutex that borrows the memory for its underlying mutex. The underlying mutex will not be
destroyed when
BorrowedMutexis dropped. It is the caller’s responsibility to calldestroywhen the mutex is no longer needed. - Owned
Mutex - A mutex that owns its underlying raw mutex. Dropping the
OwnedMutexdestroys it, provided nobody still holds the lock: destroying a locked mutex is undefined, so a guard that was leaked rather than dropped leaks the pthread object with it. If you want to construct a mutex in shared memory for IPC, use aBorrowedMutexinstead. - RawMutex
Alloc - Cast to a pointer of this type when constructing a mutex from a raw pointer.
Enums§
- Mutex
Lock Error - The error type returned on failed mutex locks.