Skip to main content

Module mutex

Module mutex 

Source
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:

OwnedMutexBorrowedMutex
Implements Copy?NoYes
Destroys underlying mutex on drop?When unlockedNever
Can be used for shared memory IPC?NoYes
Can be used without unsafe?YesNo

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 MutexBuilder along 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§

BorrowedMutex
A mutex that borrows the memory for its underlying mutex. The underlying mutex will not be destroyed when BorrowedMutex is dropped. It is the caller’s responsibility to call destroy when the mutex is no longer needed.
OwnedMutex
A mutex that owns its underlying raw mutex. Dropping the OwnedMutex destroys 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 a BorrowedMutex instead.
RawMutexAlloc
Cast to a pointer of this type when constructing a mutex from a raw pointer.

Enums§

MutexLockError
The error type returned on failed mutex locks.