• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::CriticalSection;
2 use 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)]
74 pub 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 
86 impl<T> Mutex<T> {
87     /// Creates a new mutex.
88     #[inline]
new(value: T) -> Self89     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]
get_mut(&mut self) -> &mut T102     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]
into_inner(self) -> T108     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]
borrow<'cs>(&'cs self, _cs: CriticalSection<'cs>) -> &'cs T114     pub fn borrow<'cs>(&'cs self, _cs: CriticalSection<'cs>) -> &'cs T {
115         unsafe { &*self.inner.get() }
116     }
117 }
118 
119 impl<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]
replace<'cs>(&'cs self, cs: CriticalSection<'cs>, t: T) -> T130     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]
replace_with<'cs, F>(&'cs self, cs: CriticalSection<'cs>, f: F) -> T where F: FnOnce(&mut T) -> T,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]
borrow_ref<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, T>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]
borrow_ref_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, T>175     pub fn borrow_ref_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, T> {
176         self.borrow(cs).borrow_mut()
177     }
178 }
179 
180 impl<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]
take<'cs>(&'cs self, cs: CriticalSection<'cs>) -> T191     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.
199 unsafe 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)]
208 const BorrowMustNotOutliveMutexTest: () = ();
209