lock_api/lib.rs
1//! This library provides type-safe and fully-featured [`Mutex`], [`RwLock`],
2//! and [`Condvar`] types which wrap simple raw synchronization primitives. This
3//! has several
4//! benefits: not only does it eliminate a large portion of the work in
5//! implementing custom lock types, it also allows users to write code which is
6//! generic with regard to different lock implementations.
7//!
8//! Basic usage of this crate is very straightforward:
9//!
10//! 1. Create a raw lock type. This should only contain the lock state, not any
11//! data protected by the lock.
12//! 2. Implement the `RawMutex` trait for your custom lock type.
13//! 3. Export your mutex as a type alias for `lock_api::Mutex`, and
14//! your mutex guard as a type alias for `lock_api::MutexGuard`.
15//! See the [example](#example) below for details.
16//!
17//! This process is similar for [`RwLock`]s, except that two guards need to be
18//! exported instead of one (or three guards if your type supports upgradable
19//! read locks; see [extension traits](#extension-traits) below for details).
20//! A [`Condvar`] additionally requires a [`RawCondvar`] implementation tied to
21//! the raw mutex type with which it can be used.
22//!
23//! # Example
24//!
25//! ```
26//! use lock_api::{RawMutex, Mutex, GuardSend};
27//! use std::sync::atomic::{AtomicBool, Ordering};
28//!
29//! // 1. Define our raw lock type
30//! pub struct RawSpinlock(AtomicBool);
31//!
32//! // 2. Implement RawMutex for this type
33//! unsafe impl RawMutex for RawSpinlock {
34//! const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false));
35//!
36//! // A spinlock guard can be sent to another thread and unlocked there
37//! type Guard = GuardSend;
38//!
39//! fn lock(&self) -> Self::Guard {
40//! // Note: This isn't the best way of implementing a spinlock, but it
41//! // suffices for the sake of this example.
42//! loop {
43//! if let Some(guard) = self.try_lock() {
44//! return guard;
45//! }
46//! }
47//! }
48//!
49//! fn try_lock(&self) -> Option<Self::Guard> {
50//! self.0
51//! .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
52//! .ok().map(|_| GuardSend::new())
53//! }
54//!
55//! unsafe fn unlock(&self, _guard: Self::Guard) {
56//! self.0.store(false, Ordering::Release);
57//! }
58//!
59//! fn is_locked(&self) -> bool {
60//! self.0.load(Ordering::Relaxed)
61//! }
62//! }
63//!
64//! // 3. Export the wrappers. These are the types that users will actually use.
65//! pub type Spinlock<T> = lock_api::Mutex<RawSpinlock, T>;
66//! pub type SpinlockGuard<'a, T> = lock_api::MutexGuard<'a, RawSpinlock, T>;
67//! ```
68//!
69//! # Extension traits
70//!
71//! In addition to basic locking & unlocking functionality, you have the option
72//! of exposing additional functionality in your lock types by implementing
73//! additional traits for it. Examples of extension features include:
74//!
75//! - Fair unlocking ([`RawMutexFair`], [`RawRwLockFair`])
76//! - Lock timeouts ([`RawMutexTimed`], [`RawRwLockTimed`])
77//! - Condition-variable timeouts ([`RawCondvarTimed`])
78//! - Downgradable write locks ([`RawRwLockDowngrade`])
79//! - Upgradable read locks ([`RawRwLockUpgrade`])
80//!
81//! The `Mutex` and `RwLock` wrappers will automatically expose this additional
82//! functionality if the raw lock type implements these extension traits.
83//!
84//! # Cargo features
85//!
86//! This crate provides the following Cargo features:
87//!
88//! - `atomic_usize`: Enables reentrant mutex types, which require pointer-sized
89//! atomic operations. This feature is enabled by default.
90//! - `arc_lock`: Enables locking from an `Arc` and types such as
91//! `ArcMutexGuard`. This requires the `alloc` crate.
92//! - `owning_ref`: Allows lock guards to be used with the `owning_ref` crate.
93//! - `serde`: Enables serialization and deserialization of lock types.
94
95#![no_std]
96#![cfg_attr(docsrs, feature(doc_cfg))]
97#![warn(missing_docs)]
98#![warn(rust_2018_idioms)]
99
100#[cfg(feature = "arc_lock")]
101extern crate alloc;
102
103/// A stateless guard which is [`Send`].
104#[derive(Default)]
105pub struct GuardSend(());
106
107impl GuardSend {
108 /// Creates a stateless guard which can be sent to another thread.
109 #[inline]
110 pub const fn new() -> Self {
111 Self(())
112 }
113}
114
115/// A stateless guard which is not [`Send`].
116#[derive(Default)]
117pub struct GuardNoSend(core::marker::PhantomData<*mut ()>);
118
119impl GuardNoSend {
120 /// Creates a stateless guard which cannot be sent to another thread.
121 #[inline]
122 pub const fn new() -> Self {
123 Self(core::marker::PhantomData)
124 }
125}
126
127unsafe impl Sync for GuardNoSend {}
128
129// scopeguard's defer! defines its closure in Rust 2015, so it captures entire
130// variables instead of individual fields. Define it locally to use our
131// edition's precise captures, allowing cleanup to borrow one field while
132// another is used.
133macro_rules! defer {
134 ($($t:tt)*) => {
135 let _guard = scopeguard::guard((), |()| { $($t)* });
136 };
137}
138
139mod guard;
140mod mutex;
141pub use crate::mutex::*;
142
143#[cfg(feature = "atomic_usize")]
144mod remutex;
145#[cfg(feature = "atomic_usize")]
146pub use crate::remutex::*;
147
148mod rwlock;
149pub use crate::rwlock::*;
150
151mod condvar;
152pub use crate::condvar::*;