critical_section/
mutex.rs

1use super::CriticalSection;
2use core::cell::{Ref, RefCell, RefMut, UnsafeCell};
3
4/// A mutex based on critical sections.
5///
6/// # Example
7///
8/// ```no_run
9/// # use critical_section::Mutex;
10/// # use std::cell::Cell;
11///
12/// static FOO: Mutex<Cell<i32>> = Mutex::new(Cell::new(42));
13///
14/// fn main() {
15///     critical_section::with(|cs| {
16///         FOO.borrow(cs).set(43);
17///     });
18/// }
19///
20/// fn interrupt_handler() {
21///     let _x = critical_section::with(|cs| FOO.borrow(cs).get());
22/// }
23/// ```
24///
25///
26/// # Design
27///
28/// [`std::sync::Mutex`] has two purposes. It converts types that are [`Send`]
29/// but not [`Sync`] into types that are both; and it provides
30/// [interior mutability]. `critical_section::Mutex`, on the other hand, only adds
31/// `Sync`. It does *not* provide interior mutability.
32///
33/// This was a conscious design choice. It is possible to create multiple
34/// [`CriticalSection`] tokens, either by nesting critical sections or `Copy`ing
35/// an existing token. As a result, it would not be sound for [`Mutex::borrow`]
36/// to return `&mut T`, because there would be nothing to prevent calling
37/// `borrow` multiple times to create aliased `&mut T` references.
38///
39/// The solution is to include a runtime check to ensure that each resource is
40/// borrowed only once. This is what `std::sync::Mutex` does. However, this is
41/// a runtime cost that may not be required in all circumstances. For instance,
42/// `Mutex<Cell<T>>` never needs to create `&mut T` or equivalent.
43///
44/// If `&mut T` is needed, the simplest solution is to use `Mutex<RefCell<T>>`,
45/// which is the closest analogy to `std::sync::Mutex`. [`RefCell`] inserts the
46/// exact runtime check necessary to guarantee that the `&mut T` reference is
47/// unique.
48///
49/// To reduce verbosity when using `Mutex<RefCell<T>>`, we reimplement some of
50/// `RefCell`'s methods on it directly.
51///
52/// ```no_run
53/// # use critical_section::Mutex;
54/// # use std::cell::RefCell;
55///
56/// static FOO: Mutex<RefCell<i32>> = Mutex::new(RefCell::new(42));
57///
58/// fn main() {
59///     critical_section::with(|cs| {
60///         // Instead of calling this
61///         let _ = FOO.borrow(cs).take();
62///         // Call this
63///         let _ = FOO.take(cs);
64///         // `RefCell::borrow` and `RefCell::borrow_mut` are renamed to
65///         // `borrow_ref` and `borrow_ref_mut` to avoid name collisions
66///         let _: &mut i32 = &mut *FOO.borrow_ref_mut(cs);
67///     })
68/// }
69/// ```
70///
71/// [`std::sync::Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
72/// [interior mutability]: https://doc.rust-lang.org/reference/interior-mutability.html
73#[derive(Debug)]
74pub struct Mutex<T> {
75    // The `UnsafeCell` is not strictly necessary here: In theory, just using `T` should
76    // be fine.
77    // However, without `UnsafeCell`, the compiler may use niches inside `T`, and may
78    // read the niche value _without locking the mutex_. As we don't provide interior
79    // mutability, this is still not violating any aliasing rules and should be perfectly
80    // fine. But as the cost of adding `UnsafeCell` is very small, we add it out of
81    // cautiousness, just in case the reason `T` is not `Sync` in the first place is
82    // something very obscure we didn't consider.
83    inner: UnsafeCell<T>,
84}
85
86impl<T> Mutex<T> {
87    /// Creates a new mutex.
88    #[inline]
89    pub const fn new(value: T) -> Self {
90        Mutex {
91            inner: UnsafeCell::new(value),
92        }
93    }
94
95    /// Gets a mutable reference to the contained value when the mutex is already uniquely borrowed.
96    ///
97    /// This does not require locking or a critical section since it takes `&mut self`, which
98    /// guarantees unique ownership already. Care must be taken when using this method to
99    /// **unsafely** access `static mut` variables, appropriate fences must be used to prevent
100    /// unwanted optimizations.
101    #[inline]
102    pub fn get_mut(&mut self) -> &mut T {
103        unsafe { &mut *self.inner.get() }
104    }
105
106    /// Unwraps the contained value, consuming the mutex.
107    #[inline]
108    pub fn into_inner(self) -> T {
109        self.inner.into_inner()
110    }
111
112    /// Borrows the data for the duration of the critical section.
113    #[inline]
114    pub fn borrow<'cs>(&'cs self, _cs: CriticalSection<'cs>) -> &'cs T {
115        unsafe { &*self.inner.get() }
116    }
117}
118
119impl<T> Mutex<RefCell<T>> {
120    /// Borrow the data and call [`RefCell::replace`]
121    ///
122    /// This is equivalent to `self.borrow(cs).replace(t)`
123    ///
124    /// # Panics
125    ///
126    /// This call could panic. See the documentation for [`RefCell::replace`]
127    /// for more details.
128    #[inline]
129    #[track_caller]
130    pub fn replace<'cs>(&'cs self, cs: CriticalSection<'cs>, t: T) -> T {
131        self.borrow(cs).replace(t)
132    }
133
134    /// Borrow the data and call [`RefCell::replace_with`]
135    ///
136    /// This is equivalent to `self.borrow(cs).replace_with(f)`
137    ///
138    /// # Panics
139    ///
140    /// This call could panic. See the documentation for
141    /// [`RefCell::replace_with`] for more details.
142    #[inline]
143    #[track_caller]
144    pub fn replace_with<'cs, F>(&'cs self, cs: CriticalSection<'cs>, f: F) -> T
145    where
146        F: FnOnce(&mut T) -> T,
147    {
148        self.borrow(cs).replace_with(f)
149    }
150
151    /// Borrow the data and call [`RefCell::borrow`]
152    ///
153    /// This is equivalent to `self.borrow(cs).borrow()`
154    ///
155    /// # Panics
156    ///
157    /// This call could panic. See the documentation for [`RefCell::borrow`]
158    /// for more details.
159    #[inline]
160    #[track_caller]
161    pub fn borrow_ref<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, T> {
162        self.borrow(cs).borrow()
163    }
164
165    /// Borrow the data and call [`RefCell::borrow_mut`]
166    ///
167    /// This is equivalent to `self.borrow(cs).borrow_mut()`
168    ///
169    /// # Panics
170    ///
171    /// This call could panic. See the documentation for [`RefCell::borrow_mut`]
172    /// for more details.
173    #[inline]
174    #[track_caller]
175    pub fn borrow_ref_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, T> {
176        self.borrow(cs).borrow_mut()
177    }
178}
179
180impl<T: Default> Mutex<RefCell<T>> {
181    /// Borrow the data and call [`RefCell::take`]
182    ///
183    /// This is equivalent to `self.borrow(cs).take()`
184    ///
185    /// # Panics
186    ///
187    /// This call could panic. See the documentation for [`RefCell::take`]
188    /// for more details.
189    #[inline]
190    #[track_caller]
191    pub fn take<'cs>(&'cs self, cs: CriticalSection<'cs>) -> T {
192        self.borrow(cs).take()
193    }
194}
195
196// NOTE A `Mutex` can be used as a channel so the protected data must be `Send`
197// to prevent sending non-Sendable stuff (e.g. access tokens) across different
198// threads.
199unsafe impl<T> Sync for Mutex<T> where T: Send {}
200
201/// ``` compile_fail
202/// fn bad(cs: critical_section::CriticalSection) -> &u32 {
203///     let x = critical_section::Mutex::new(42u32);
204///     x.borrow(cs)
205/// }
206/// ```
207#[cfg(doctest)]
208const BorrowMustNotOutliveMutexTest: () = ();