Skip to content

Commit 5898d7f

Browse files
authored
Add docs to help choosing a lock impl (#20)
* Add docs to help choosing a lock impl Also enables features for docsrs so all impls are shown * Fix typo
1 parent 60fc639 commit 5898d7f

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

source/mutex/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repository.workspace = true
1515

1616
[package.metadata.docs.rs]
1717
all-features = true
18-
rustdoc-args = ["--cfg", "docsrs"]
18+
rustdoc-args = ["--cfg", "docsrs", "--cfg", "cortex_m"]
1919

2020
[dependencies.mutex-traits]
2121
version = "1.0.0"

source/mutex/src/raw_impls.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,68 @@
55
//!
66
//! [`ScopedRawMutex`]: crate::ScopedRawMutex
77
//! [`RawMutex`]: crate::RawMutex
8+
//!
9+
//! ## Which impl should I use?
10+
//!
11+
//! This module contains different implementations based on their capabilities and what
12+
//! features or dependencies they require.
13+
//!
14+
//! ### `local` impl
15+
//!
16+
//! The [`local`] module implements a mutex that acts similarly to a `RefCell`, and is
17+
//! useful when a type requires a [`ScopedRawMutex`], but the item is only ever used locally
18+
//! within the same thread or task. This implementation does NOT impl `Sync`, so it cannot
19+
//! be placed in a static. Because this property is checkable at compile time, this mutex
20+
//! has the lowest overall cost to lock/unlock.
21+
//!
22+
//! This module requires no features to be enabled.
23+
//!
24+
//! ### `single_core_thread_mode` impl
25+
//!
26+
//! The [`single_core_thread_mode`] module implements a mutex that DOES impl `Sync`, but
27+
//! only allows access when NOT in interrupt mode, e.g. "thread mode" on cortex-m devices.
28+
//! This property is useful when you'd like to place a mutex in a static for lifetime or
29+
//! accessibility reasons, but don't want to require a critical section to access, if all
30+
//! access is done outside of interrupt context. This requires a runtime check, making it
31+
//! a bit less efficient than the [`local`] impl, but less costly or disruptive than
32+
//! taking a critical section.
33+
//!
34+
//! This impl is currently only usable on bare metal cortex-m targets, as it checks the
35+
//! `ICSR.VECTACTIVE` field at runtime. PRs to allow similar checks for other architectures
36+
//! are welcome. This impl ALSO requires the `impl-unsafe-cortex-m-single-core` feature to
37+
//! be active, which should ONLY be enabled if your target is single core or is only being
38+
//! used in a single core configuration, otherwise both cores could unsoundly gain access
39+
//! at the same time.
40+
//!
41+
//! ### `cs` impl
42+
//!
43+
//! The [`cs`] module implements a mutex that DOES impl `Sync`, and provides exclusive
44+
//! access using a critical section via the `critical-section` crate. The `critical-section`
45+
//! crate allows users to define how a critical section can be obtained: on single core embedded
46+
//! platforms, this usually involves disabling interrupts for the duration of the critical
47+
//! section. On multicore embedded platforms, this usually involves using some hardware
48+
//! synchronization utility, for example using the "Spinlock" peripheral on RP2xxx targets.
49+
//! On desktop/`std` platforms, this typically involves using a `std` Mutex from the operating
50+
//! system, which will prevent concurrent access.
51+
//!
52+
//! This impl can be used in the widest variety of cases, but generally has the highest cost
53+
//! or largest impact to scheduling/latency. That being said: simply taking or releasing critical
54+
//! sections is rarely an expensive operation (only a few cycles on embedded targets), however if an
55+
//! expensive operation is done WHILE holding the critical section, latency of servicing interrupts
56+
//! or other threads may be impacted.
57+
//!
58+
//! This impl requires the `impl-critical-section` feature to be active, and requires that a
59+
//! `critical-section` implementation has been provided. If both the `std` and `impl-critical-section`
60+
//! features of this crate are active, the `critical-section/std` feature is enabled, fulfilling this
61+
//! requirement on std targets. For embedded targets, `critical-section` impls are usually provided
62+
//! by your architecture crate (e.g. `cortex-m`) for single core targets or HAL crate
63+
//! (e.g. `embassy-rp`) for multi-core targets.
64+
//!
65+
//! ### `lock_api_0_4`
66+
//!
67+
//! The `lock_api_0_4` module implements a mutex based on the `lock_api` crate. This is provided
68+
//! for compatibility if your system is using mutexes based on the `lock_api`/`parking_lot`
69+
//! crates. This is uncommon for embedded targets.
870
#![allow(clippy::new_without_default)]
971
#![allow(clippy::declare_interior_mutable_const)]
1072

@@ -89,7 +151,7 @@ pub mod local {
89151
#[cfg_attr(feature = "fmt", derive(Debug))]
90152
pub struct LocalRawMutex {
91153
taken: AtomicBool,
92-
/// Prevent this from being sync or send
154+
/// Prevent this from being sync
93155
_phantom: PhantomData<*mut ()>,
94156
}
95157

@@ -113,7 +175,7 @@ pub mod local {
113175
#[inline]
114176
#[must_use]
115177
fn try_with_lock<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
116-
// NOTE: separated load/stores are acceptable as we are !Send and !Sync,
178+
// NOTE: separated load/stores are acceptable as we are !Sync,
117179
// meaning that we can only be accessed within a single thread
118180
if self.taken.load(Ordering::Relaxed) {
119181
return None;

0 commit comments

Comments
 (0)