1//! Async mutex.
2//!
3//! This module provides a mutex that can be used to synchronize data between asynchronous tasks.
4use core::cell::{RefCell, UnsafeCell};
5use core::future::{poll_fn, Future};
6use core::ops::{Deref, DerefMut};
7use core::task::Poll;
8use core::{fmt, mem};
9
10use crate::blocking_mutex::raw::RawMutex;
11use crate::blocking_mutex::Mutex as BlockingMutex;
12use crate::waitqueue::WakerRegistration;
13
14/// Error returned by [`Mutex::try_lock`]
15#[derive(PartialEq, Eq, Clone, Copy, Debug)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct TryLockError;
18
19struct State {
20 locked: bool,
21 waker: WakerRegistration,
22}
23
24/// Async mutex.
25///
26/// The mutex is generic over a blocking [`RawMutex`](crate::blocking_mutex::raw::RawMutex).
27/// The raw mutex is used to guard access to the internal "is locked" flag. It
28/// is held for very short periods only, while locking and unlocking. It is *not* held
29/// for the entire time the async Mutex is locked.
30///
31/// Which implementation you select depends on the context in which you're using the mutex.
32///
33/// Use [`CriticalSectionRawMutex`](crate::blocking_mutex::raw::CriticalSectionRawMutex) when data can be shared between threads and interrupts.
34///
35/// Use [`NoopRawMutex`](crate::blocking_mutex::raw::NoopRawMutex) when data is only shared between tasks running on the same executor.
36///
37/// Use [`ThreadModeRawMutex`](crate::blocking_mutex::raw::ThreadModeRawMutex) when data is shared between tasks running on the same executor but you want a singleton.
38///
39pub struct Mutex<M, T>
40where
41 M: RawMutex,
42 T: ?Sized,
43{
44 state: BlockingMutex<M, RefCell<State>>,
45 inner: UnsafeCell<T>,
46}
47
48unsafe impl<M: RawMutex + Send, T: ?Sized + Send> Send for Mutex<M, T> {}
49unsafe impl<M: RawMutex + Sync, T: ?Sized + Send> Sync for Mutex<M, T> {}
50
51/// Async mutex.
52impl<M, T> Mutex<M, T>
53where
54 M: RawMutex,
55{
56 /// Create a new mutex with the given value.
57 pub const fn new(value: T) -> Self {
58 Self {
59 inner: UnsafeCell::new(value),
60 state: BlockingMutex::new(val:RefCell::new(State {
61 locked: false,
62 waker: WakerRegistration::new(),
63 })),
64 }
65 }
66}
67
68impl<M, T> Mutex<M, T>
69where
70 M: RawMutex,
71 T: ?Sized,
72{
73 /// Lock the mutex.
74 ///
75 /// This will wait for the mutex to be unlocked if it's already locked.
76 pub fn lock(&self) -> impl Future<Output = MutexGuard<'_, M, T>> {
77 poll_fn(|cx| {
78 let ready = self.state.lock(|s| {
79 let mut s = s.borrow_mut();
80 if s.locked {
81 s.waker.register(cx.waker());
82 false
83 } else {
84 s.locked = true;
85 true
86 }
87 });
88
89 if ready {
90 Poll::Ready(MutexGuard { mutex: self })
91 } else {
92 Poll::Pending
93 }
94 })
95 }
96
97 /// Attempt to immediately lock the mutex.
98 ///
99 /// If the mutex is already locked, this will return an error instead of waiting.
100 pub fn try_lock(&self) -> Result<MutexGuard<'_, M, T>, TryLockError> {
101 self.state.lock(|s| {
102 let mut s = s.borrow_mut();
103 if s.locked {
104 Err(TryLockError)
105 } else {
106 s.locked = true;
107 Ok(())
108 }
109 })?;
110
111 Ok(MutexGuard { mutex: self })
112 }
113
114 /// Consumes this mutex, returning the underlying data.
115 pub fn into_inner(self) -> T
116 where
117 T: Sized,
118 {
119 self.inner.into_inner()
120 }
121
122 /// Returns a mutable reference to the underlying data.
123 ///
124 /// Since this call borrows the Mutex mutably, no actual locking needs to
125 /// take place -- the mutable borrow statically guarantees no locks exist.
126 pub fn get_mut(&mut self) -> &mut T {
127 self.inner.get_mut()
128 }
129}
130
131impl<M: RawMutex, T> From<T> for Mutex<M, T> {
132 fn from(from: T) -> Self {
133 Self::new(from)
134 }
135}
136
137impl<M, T> Default for Mutex<M, T>
138where
139 M: RawMutex,
140 T: Default,
141{
142 fn default() -> Self {
143 Self::new(Default::default())
144 }
145}
146
147impl<M, T> fmt::Debug for Mutex<M, T>
148where
149 M: RawMutex,
150 T: ?Sized + fmt::Debug,
151{
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 let mut d: DebugStruct<'_, '_> = f.debug_struct(name:"Mutex");
154 match self.try_lock() {
155 Ok(value: MutexGuard<'_, M, T>) => {
156 d.field(name:"inner", &&*value);
157 }
158 Err(TryLockError) => {
159 d.field(name:"inner", &format_args!("<locked>"));
160 }
161 }
162
163 d.finish_non_exhaustive()
164 }
165}
166
167/// Async mutex guard.
168///
169/// Owning an instance of this type indicates having
170/// successfully locked the mutex, and grants access to the contents.
171///
172/// Dropping it unlocks the mutex.
173#[clippy::has_significant_drop]
174pub struct MutexGuard<'a, M, T>
175where
176 M: RawMutex,
177 T: ?Sized,
178{
179 mutex: &'a Mutex<M, T>,
180}
181
182impl<'a, M, T> MutexGuard<'a, M, T>
183where
184 M: RawMutex,
185 T: ?Sized,
186{
187 /// Returns a locked view over a portion of the locked data.
188 pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
189 let mutex: &'a Mutex = this.mutex;
190 let value: &mut U = fun(unsafe { &mut *this.mutex.inner.get() });
191 // Don't run the `drop` method for MutexGuard. The ownership of the underlying
192 // locked state is being moved to the returned MappedMutexGuard.
193 mem::forget(this);
194 MappedMutexGuard {
195 state: &mutex.state,
196 value,
197 }
198 }
199}
200
201impl<'a, M, T> Drop for MutexGuard<'a, M, T>
202where
203 M: RawMutex,
204 T: ?Sized,
205{
206 fn drop(&mut self) {
207 self.mutex.state.lock(|s: &RefCell| {
208 let mut s = unwrap!(s.try_borrow_mut());
209 s.locked = false;
210 s.waker.wake();
211 })
212 }
213}
214
215impl<'a, M, T> Deref for MutexGuard<'a, M, T>
216where
217 M: RawMutex,
218 T: ?Sized,
219{
220 type Target = T;
221 fn deref(&self) -> &Self::Target {
222 // Safety: the MutexGuard represents exclusive access to the contents
223 // of the mutex, so it's OK to get it.
224 unsafe { &*(self.mutex.inner.get() as *const T) }
225 }
226}
227
228impl<'a, M, T> DerefMut for MutexGuard<'a, M, T>
229where
230 M: RawMutex,
231 T: ?Sized,
232{
233 fn deref_mut(&mut self) -> &mut Self::Target {
234 // Safety: the MutexGuard represents exclusive access to the contents
235 // of the mutex, so it's OK to get it.
236 unsafe { &mut *(self.mutex.inner.get()) }
237 }
238}
239
240impl<'a, M, T> fmt::Debug for MutexGuard<'a, M, T>
241where
242 M: RawMutex,
243 T: ?Sized + fmt::Debug,
244{
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 fmt::Debug::fmt(&**self, f)
247 }
248}
249
250impl<'a, M, T> fmt::Display for MutexGuard<'a, M, T>
251where
252 M: RawMutex,
253 T: ?Sized + fmt::Display,
254{
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 fmt::Display::fmt(&**self, f)
257 }
258}
259
260/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or
261/// [`MappedMutexGuard::map`].
262///
263/// This can be used to hold a subfield of the protected data.
264#[clippy::has_significant_drop]
265pub struct MappedMutexGuard<'a, M, T>
266where
267 M: RawMutex,
268 T: ?Sized,
269{
270 state: &'a BlockingMutex<M, RefCell<State>>,
271 value: *mut T,
272}
273
274impl<'a, M, T> MappedMutexGuard<'a, M, T>
275where
276 M: RawMutex,
277 T: ?Sized,
278{
279 /// Returns a locked view over a portion of the locked data.
280 pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
281 let state: &'a Mutex> = this.state;
282 let value: &mut U = fun(unsafe { &mut *this.value });
283 // Don't run the `drop` method for MutexGuard. The ownership of the underlying
284 // locked state is being moved to the returned MappedMutexGuard.
285 mem::forget(this);
286 MappedMutexGuard { state, value }
287 }
288}
289
290impl<'a, M, T> Deref for MappedMutexGuard<'a, M, T>
291where
292 M: RawMutex,
293 T: ?Sized,
294{
295 type Target = T;
296 fn deref(&self) -> &Self::Target {
297 // Safety: the MutexGuard represents exclusive access to the contents
298 // of the mutex, so it's OK to get it.
299 unsafe { &*self.value }
300 }
301}
302
303impl<'a, M, T> DerefMut for MappedMutexGuard<'a, M, T>
304where
305 M: RawMutex,
306 T: ?Sized,
307{
308 fn deref_mut(&mut self) -> &mut Self::Target {
309 // Safety: the MutexGuard represents exclusive access to the contents
310 // of the mutex, so it's OK to get it.
311 unsafe { &mut *self.value }
312 }
313}
314
315impl<'a, M, T> Drop for MappedMutexGuard<'a, M, T>
316where
317 M: RawMutex,
318 T: ?Sized,
319{
320 fn drop(&mut self) {
321 self.state.lock(|s: &RefCell| {
322 let mut s = unwrap!(s.try_borrow_mut());
323 s.locked = false;
324 s.waker.wake();
325 })
326 }
327}
328
329unsafe impl<M, T> Send for MappedMutexGuard<'_, M, T>
330where
331 M: RawMutex + Sync,
332 T: Send + ?Sized,
333{
334}
335
336unsafe impl<M, T> Sync for MappedMutexGuard<'_, M, T>
337where
338 M: RawMutex + Sync,
339 T: Sync + ?Sized,
340{
341}
342
343impl<'a, M, T> fmt::Debug for MappedMutexGuard<'a, M, T>
344where
345 M: RawMutex,
346 T: ?Sized + fmt::Debug,
347{
348 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349 fmt::Debug::fmt(&**self, f)
350 }
351}
352
353impl<'a, M, T> fmt::Display for MappedMutexGuard<'a, M, T>
354where
355 M: RawMutex,
356 T: ?Sized + fmt::Display,
357{
358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359 fmt::Display::fmt(&**self, f)
360 }
361}
362
363#[cfg(test)]
364mod tests {
365 use crate::blocking_mutex::raw::NoopRawMutex;
366 use crate::mutex::{Mutex, MutexGuard};
367
368 #[futures_test::test]
369 async fn mapped_guard_releases_lock_when_dropped() {
370 let mutex: Mutex<NoopRawMutex, [i32; 2]> = Mutex::new([0, 1]);
371
372 {
373 let guard = mutex.lock().await;
374 assert_eq!(*guard, [0, 1]);
375 let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
376 assert_eq!(*mapped, 1);
377 *mapped = 2;
378 }
379
380 {
381 let guard = mutex.lock().await;
382 assert_eq!(*guard, [0, 2]);
383 let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
384 assert_eq!(*mapped, 2);
385 *mapped = 3;
386 }
387
388 assert_eq!(*mutex.lock().await, [0, 3]);
389 }
390}
391