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