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 ] |
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 | |
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 ] |
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 | |
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 ] |
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. |
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 | |