sync_linux_no_libc/sync/
mutex.rs

1use crate::sys;
2use core::cell::UnsafeCell;
3use core::error::Error;
4use core::fmt;
5use core::ops::{Deref, DerefMut};
6
7/// An enumeration of possible errors associated with a [`TryLockResult`] which
8/// can occur while trying to acquire a lock, from the [`try_lock`] method on a
9/// [`Mutex`].
10///
11/// [`try_lock`]: Mutex::try_lock
12/// [`Mutex`]: Mutex
13pub enum TryLockError {
14    /// The lock could not be acquired at this time because the operation would
15    /// otherwise block.
16    WouldBlock,
17}
18
19impl fmt::Debug for TryLockError {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        match *self {
22            TryLockError::WouldBlock => "WouldBlock".fmt(f),
23        }
24    }
25}
26
27impl fmt::Display for TryLockError {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        match *self {
30            TryLockError::WouldBlock => "try_lock failed because the operation would block",
31        }.fmt(f)
32    }
33}
34
35impl Error for TryLockError {
36    #[allow(deprecated, deprecated_in_future)]
37    fn description(&self) -> &str {
38        match *self {
39            TryLockError::WouldBlock => "try_lock failed because the operation would block",
40        }
41    }
42
43    #[allow(deprecated)]
44    fn cause(&self) -> Option<&dyn Error> {
45        None
46    }
47}
48
49/// A type alias for the result of a nonblocking locking method.
50pub type TryLockResult<Guard> = Result<Guard, TryLockError>;
51
52/// A mutual exclusion primitive useful for protecting shared data
53///
54/// This mutex will block threads waiting for the lock to become available. The
55/// mutex can be created via a [`new`] constructor. Each mutex has a type parameter
56/// which represents the data that it is protecting. The data can only be accessed
57/// through the RAII guards returned from [`lock`] and [`try_lock`], which
58/// guarantees that the data is only ever accessed when the mutex is locked.
59///
60/// # Poisoning
61///
62/// This implementation of the mutex does not implement poisoning, as it might not
63/// be possible to do in a no_std environment. This puts the responsibility of never
64/// tainting the held data on the user of the mutex.
65///
66/// [`new`]: Self::new
67/// [`lock`]: Self::lock
68/// [`try_lock`]: Self::try_lock
69/// # Examples
70///
71/// ```
72/// use sync_linux_no_libc::sync::Mutex;
73/// use std::sync::{Arc};
74/// use std::thread;
75/// use std::sync::mpsc::channel;
76///
77/// const N: usize = 10;
78///
79/// // Spawn a few threads to increment a shared variable (non-atomically), and
80/// // let the main thread know once all increments are done.
81/// //
82/// // Here we're using an Arc to share memory among threads, and the data inside
83/// // the Arc is protected with a mutex.
84/// let data = Arc::new(Mutex::new(0));
85///
86/// let (tx, rx) = channel();
87/// for _ in 0..N {
88///     let (data, tx) = (Arc::clone(&data), tx.clone());
89///     thread::spawn(move || {
90///         // The shared state can only be accessed once the lock is held.
91///         // Our non-atomic increment is safe because we're the only thread
92///         // which can access the shared state when the lock is held.
93///         //
94///         // We unwrap() the return value to assert that we are not expecting
95///         // threads to ever fail while holding the lock.
96///         let mut data = data.lock();
97///         *data += 1;
98///         if *data == N {
99///             tx.send(()).unwrap();
100///         }
101///         // the lock is unlocked here when `data` goes out of scope.
102///     });
103/// }
104///
105/// rx.recv().unwrap();
106/// ```
107///
108/// To unlock a mutex guard sooner than the end of the enclosing scope,
109/// either create an inner scope or drop the guard manually.
110///
111/// ```
112/// use sync_linux_no_libc::sync::Mutex;
113/// use std::sync::{Arc};
114/// use std::thread;
115///
116/// const N: usize = 3;
117///
118/// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
119/// let res_mutex = Arc::new(Mutex::new(0));
120///
121/// let mut threads = Vec::with_capacity(N);
122/// (0..N).for_each(|_| {
123///     let data_mutex_clone = Arc::clone(&data_mutex);
124///     let res_mutex_clone = Arc::clone(&res_mutex);
125///
126///     threads.push(thread::spawn(move || {
127///         // Here we use a block to limit the lifetime of the lock guard.
128///         let result = {
129///             let mut data = data_mutex_clone.lock();
130///             // This is the result of some important and long-ish work.
131///             let result = data.iter().fold(0, |acc, x| acc + x * 2);
132///             data.push(result);
133///             result
134///             // The mutex guard gets dropped here, together with any other values
135///             // created in the critical section.
136///         };
137///         // The guard created here is a temporary dropped at the end of the statement, i.e.
138///         // the lock would not remain being held even if the thread did some additional work.
139///         *res_mutex_clone.lock() += result;
140///     }));
141/// });
142///
143/// let mut data = data_mutex.lock();
144/// // This is the result of some important and long-ish work.
145/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
146/// data.push(result);
147/// // We drop the `data` explicitly because it's not necessary anymore and the
148/// // thread still has work to do. This allows other threads to start working on
149/// // the data immediately, without waiting for the rest of the unrelated work
150/// // to be done here.
151/// //
152/// // It's even more important here than in the threads because we `.join` the
153/// // threads after that. If we had not dropped the mutex guard, a thread could
154/// // be waiting forever for it, causing a deadlock.
155/// // As in the threads, a block could have been used instead of calling the
156/// // `drop` function.
157/// drop(data);
158/// // Here the mutex guard is not assigned to a variable and so, even if the
159/// // scope does not end after this line, the mutex is still released: there is
160/// // no deadlock.
161/// *res_mutex.lock() += result;
162///
163/// threads.into_iter().for_each(|thread| {
164///     thread
165///         .join()
166///         .expect("The thread creating or execution failed !")
167/// });
168///
169/// assert_eq!(*res_mutex.lock(), 800);
170/// ```
171///
172pub struct Mutex<T: ?Sized> {
173    inner: sys::Mutex,
174    data: UnsafeCell<T>,
175}
176
177/// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire
178/// the owned `T` from the `Mutex` via [`into_inner`].
179///
180/// [`into_inner`]: Mutex::into_inner
181unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
182
183/// `T` must be `Send` for [`Mutex`] to be `Sync`.
184/// This ensures that the protected data can be accessed safely from multiple threads
185/// without causing data races or other unsafe behavior.
186///
187/// [`Mutex<T>`] provides mutable access to `T` to one thread at a time. However, it's essential
188/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in
189/// this manner. For instance, consider [`Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html),
190/// a non-atomic reference counted smart pointer,
191/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap
192/// allocation with a non-atomic reference count. If we were to use `Mutex<Rc<_>>`, it would
193/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable
194/// to potential data races.
195///
196/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available
197/// to one thread at a time if `T` is not `Sync`.
198unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
199
200/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
201/// dropped (falls out of scope), the lock will be unlocked.
202///
203/// The data protected by the mutex can be accessed through this guard via its
204/// [`Deref`] and [`DerefMut`] implementations.
205///
206/// This structure is created by the [`lock`] and [`try_lock`] methods on
207/// [`Mutex`].
208///
209/// [`lock`]: Mutex::lock
210/// [`try_lock`]: Mutex::try_lock
211#[must_use = "if unused the Mutex will immediately unlock"]
212#[must_not_suspend = "holding a MutexGuard across suspend \
213                      points can cause deadlocks, delays, \
214                      and cause Futures to not implement `Send`"]
215#[clippy::has_significant_drop]
216pub struct MutexGuard<'a, T: ?Sized + 'a> {
217    lock: &'a Mutex<T>,
218}
219
220/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
221/// release mutex locks on the same thread they were acquired.
222/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from
223/// another thread.
224impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
225
226/// `T` must be `Sync` for a [`MutexGuard<T>`] to be `Sync`
227/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`).
228unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
229
230impl<T> Mutex<T> {
231    /// Creates a new mutex in an unlocked state ready for use.
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// use sync_linux_no_libc::sync::Mutex;
237    ///
238    /// let mutex = Mutex::new(0);
239    /// ```
240    #[inline]
241    pub const fn new(t: T) -> Mutex<T> {
242        Mutex { inner: sys::Mutex::new(), data: UnsafeCell::new(t) }
243    }
244}
245
246impl<T: ?Sized> Mutex<T> {
247    /// Acquires a mutex, blocking the current thread until it is able to do so.
248    ///
249    /// This function will block the local thread until it is available to acquire
250    /// the mutex. Upon returning, the thread is the only thread with the lock
251    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
252    /// the guard goes out of scope, the mutex will be unlocked.
253    ///
254    /// The exact behavior on locking a mutex in the thread which already holds
255    /// the lock is left unspecified. However, this function will not return on
256    /// the second call (it might panic or deadlock, for example).
257    ///
258    /// # Panics
259    ///
260    /// This function might panic when called if the lock is already held by
261    /// the current thread.
262    ///
263    /// # Examples
264    ///
265    /// ```
266    /// use sync_linux_no_libc::sync::Mutex;
267    /// use std::sync::{Arc};
268    /// use std::thread;
269    ///
270    /// let mutex = Arc::new(Mutex::new(0));
271    /// let c_mutex = Arc::clone(&mutex);
272    ///
273    /// thread::spawn(move || {
274    ///     *c_mutex.lock() = 10;
275    /// }).join().expect("thread::spawn failed");
276    /// assert_eq!(*mutex.lock(), 10);
277    /// ```
278    pub fn lock(&self) -> MutexGuard<'_, T> {
279        unsafe {
280            self.inner.lock();
281            MutexGuard::new(self)
282        }
283    }
284
285    /// Attempts to acquire this lock.
286    ///
287    /// If the lock could not be acquired at this time, then [`Err`] is returned.
288    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
289    /// guard is dropped.
290    ///
291    /// This function does not block.
292    ///
293    /// # Errors
294    ///
295    /// If the mutex could not be acquired because it is already locked, then
296    /// this call will return the [`WouldBlock`] error.
297    ///
298    /// [`WouldBlock`]: TryLockError::WouldBlock
299    ///
300    /// # Examples
301    ///
302    /// ```
303    /// use sync_linux_no_libc::sync::Mutex;
304    /// use std::sync::{Arc};
305    /// use std::thread;
306    ///
307    /// let mutex = Arc::new(Mutex::new(0));
308    /// let c_mutex = Arc::clone(&mutex);
309    ///
310    /// thread::spawn(move || {
311    ///     let mut lock = c_mutex.try_lock();
312    ///     if let Ok(ref mut mutex) = lock {
313    ///         **mutex = 10;
314    ///     } else {
315    ///         println!("try_lock failed");
316    ///     }
317    /// }).join().expect("thread::spawn failed");
318    /// assert_eq!(*mutex.lock(), 10);
319    /// ```
320    pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
321        unsafe {
322            if self.inner.try_lock() {
323                Ok(MutexGuard::new(self))
324            } else {
325                Err(TryLockError::WouldBlock)
326            }
327        }
328    }
329
330    /// Consumes this mutex, returning the underlying data.
331    ///
332    /// # Examples
333    ///
334    /// ```
335    /// use sync_linux_no_libc::sync::Mutex;
336    ///
337    /// let mutex = Mutex::new(0);
338    /// assert_eq!(mutex.into_inner(), 0);
339    /// ```
340    pub fn into_inner(self) -> T
341    where
342        T: Sized,
343    {
344        self.data.into_inner()
345    }
346
347    /// Returns a mutable reference to the underlying data.
348    ///
349    /// Since this call borrows the `Mutex` mutably, no actual locking needs to
350    /// take place -- the mutable borrow statically guarantees no new locks can be acquired
351    /// while this reference exists. Note that this method does not clear any previous abandoned locks
352    /// (e.g., via [`forget()`] on a [`MutexGuard`]).
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// use sync_linux_no_libc::sync::Mutex;
358    ///
359    /// let mut mutex = Mutex::new(0);
360    /// *mutex.get_mut() = 10;
361    /// assert_eq!(*mutex.lock(), 10);
362    /// ```
363    ///
364    /// [`forget()`]: core::mem::forget
365    pub fn get_mut(&mut self) -> &mut T {
366        self.data.get_mut()
367    }
368}
369
370impl<T> From<T> for Mutex<T> {
371    /// Creates a new mutex in an unlocked state ready for use.
372    /// This is equivalent to [`Mutex::new`].
373    fn from(t: T) -> Self {
374        Mutex::new(t)
375    }
376}
377
378impl<T: ?Sized + Default> Default for Mutex<T> {
379    /// Creates a `Mutex<T>`, with the `Default` value for T.
380    fn default() -> Mutex<T> {
381        Mutex::new(Default::default())
382    }
383}
384
385impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
386    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387        let mut d = f.debug_struct("Mutex");
388        match self.try_lock() {
389            Ok(guard) => {
390                d.field("data", &&*guard);
391            }
392            Err(TryLockError::WouldBlock) => {
393                d.field("data", &format_args!("<locked>"));
394            }
395        }
396        d.finish_non_exhaustive()
397    }
398}
399
400impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
401    unsafe fn new(lock: &'mutex Mutex<T>) -> MutexGuard<'mutex, T> {
402        MutexGuard { lock }
403    }
404}
405
406impl<T: ?Sized> Deref for MutexGuard<'_, T> {
407    type Target = T;
408
409    fn deref(&self) -> &T {
410        unsafe { &*self.lock.data.get() }
411    }
412}
413
414impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
415    fn deref_mut(&mut self) -> &mut T {
416        unsafe { &mut *self.lock.data.get() }
417    }
418}
419
420impl<T: ?Sized> Drop for MutexGuard<'_, T> {
421    #[inline]
422    fn drop(&mut self) {
423        unsafe {
424            self.lock.inner.unlock();
425        }
426    }
427}
428
429impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
430    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431        fmt::Debug::fmt(&**self, f)
432    }
433}
434
435impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
436    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437        (**self).fmt(f)
438    }
439}
440
441pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
442    &guard.lock.inner
443}