Skip to main content

spin/
mutex.rs

1//! Locks that have the same behaviour as a mutex.
2//!
3//! The [`Mutex`] in the root of the crate can be configured using the `use_ticket_mutex` feature.
4//! If enabled, its implementation will be swapped out for [`TicketMutex`] and [`TicketMutexGuard`].
5//! This may be desirable on some platforms of workloads where regular spin mutexes have
6//! particularly poor behaviour and regularly starve threads. `ticket_mutex` is disabled by default.
7//!
8//! [`Mutex`]: ./struct.Mutex.html
9//! [`MutexGuard`]: ./struct.MutexGuard.html
10//! [`TicketMutex`]: ./ticket/struct.TicketMutex.html
11//! [`TicketMutexGuard`]: ./ticket/struct.TicketMutexGuard.html
12//! [`SpinMutex`]: ./spin/struct.SpinMutex.html
13//! [`SpinMutexGuard`]: ./spin/struct.SpinMutexGuard.html
14
15#[cfg(feature = "spin_mutex")]
16#[cfg_attr(docsrs, doc(cfg(feature = "spin_mutex")))]
17pub mod spin;
18#[cfg(feature = "spin_mutex")]
19#[cfg_attr(docsrs, doc(cfg(feature = "spin_mutex")))]
20pub use self::spin::{SpinMutex, SpinMutexGuard};
21
22#[cfg(feature = "ticket_mutex")]
23#[cfg_attr(docsrs, doc(cfg(feature = "ticket_mutex")))]
24pub mod ticket;
25#[cfg(feature = "ticket_mutex")]
26#[cfg_attr(docsrs, doc(cfg(feature = "ticket_mutex")))]
27pub use self::ticket::{TicketMutex, TicketMutexGuard};
28
29#[cfg(feature = "fair_mutex")]
30#[cfg_attr(docsrs, doc(cfg(feature = "fair_mutex")))]
31pub mod fair;
32#[cfg(feature = "fair_mutex")]
33#[cfg_attr(docsrs, doc(cfg(feature = "fair_mutex")))]
34pub use self::fair::{FairMutex, FairMutexGuard, Starvation};
35
36use crate::{RelaxStrategy, Spin};
37use core::{
38    fmt,
39    ops::{Deref, DerefMut},
40};
41
42#[cfg(all(not(feature = "spin_mutex"), not(feature = "use_ticket_mutex")))]
43compile_error!("The `mutex` feature flag was used (perhaps through another feature?) without either `spin_mutex` or `use_ticket_mutex`. One of these is required.");
44
45#[cfg(all(not(feature = "use_ticket_mutex"), feature = "spin_mutex"))]
46type InnerMutex<T, R> = self::spin::SpinMutex<T, R>;
47#[cfg(all(not(feature = "use_ticket_mutex"), feature = "spin_mutex"))]
48type InnerMutexGuard<'a, T, R> = self::spin::SpinMutexGuard<'a, T, R>;
49
50#[cfg(feature = "use_ticket_mutex")]
51type InnerMutex<T, R> = self::ticket::TicketMutex<T, R>;
52#[cfg(feature = "use_ticket_mutex")]
53type InnerMutexGuard<'a, T, R> = self::ticket::TicketMutexGuard<'a, T, R>;
54
55/// A spin-based lock providing mutually exclusive access to data.
56///
57/// The implementation uses either a ticket mutex or a regular spin mutex depending on whether the `spin_mutex` or
58/// `ticket_mutex` feature flag is enabled.
59///
60/// # Example
61///
62/// ```
63/// use spin;
64///
65/// let lock = spin::Mutex::new(0);
66///
67/// // Modify the data
68/// *lock.lock() = 2;
69///
70/// // Read the data
71/// let answer = *lock.lock();
72/// assert_eq!(answer, 2);
73/// ```
74///
75/// # Thread safety example
76///
77/// ```
78/// use spin;
79/// use std::sync::{Arc, Barrier};
80///
81/// let thread_count = 1000;
82/// let spin_mutex = Arc::new(spin::Mutex::new(0));
83///
84/// // We use a barrier to ensure the readout happens after all writing
85/// let barrier = Arc::new(Barrier::new(thread_count + 1));
86///
87/// # let mut ts = Vec::new();
88/// for _ in 0..thread_count {
89///     let my_barrier = barrier.clone();
90///     let my_lock = spin_mutex.clone();
91/// # let t =
92///     std::thread::spawn(move || {
93///         let mut guard = my_lock.lock();
94///         *guard += 1;
95///
96///         // Release the lock to prevent a deadlock
97///         drop(guard);
98///         my_barrier.wait();
99///     });
100/// # ts.push(t);
101/// }
102///
103/// barrier.wait();
104///
105/// let answer = { *spin_mutex.lock() };
106/// assert_eq!(answer, thread_count);
107///
108/// # for t in ts {
109/// #     t.join().unwrap();
110/// # }
111/// ```
112pub struct Mutex<T: ?Sized, R = Spin> {
113    inner: InnerMutex<T, R>,
114}
115
116/// A generic guard that will protect some data access and
117/// uses either a ticket lock or a normal spin mutex.
118///
119/// For more info see [`TicketMutexGuard`] or [`SpinMutexGuard`].
120pub struct MutexGuard<'a, T: 'a + ?Sized, R = Spin> {
121    inner: InnerMutexGuard<'a, T, R>,
122}
123
124// SAFETY: Same unsafe impls as `std::sync::Mutex`
125unsafe impl<T: ?Sized + Send, R> Sync for Mutex<T, R> {}
126unsafe impl<T: ?Sized + Send, R> Send for Mutex<T, R> {}
127
128// SAFETY: Mutex guards can be thought of as mutable reference to the inner data. In fact, this
129// would be their ideal representation if it were not for the need for the critical section to end
130// *after* the reference is no longer live.
131unsafe impl<T: ?Sized, R> Sync for MutexGuard<'_, T, R> where for<'a> &'a mut T: Sync {}
132unsafe impl<T: ?Sized, R> Send for MutexGuard<'_, T, R> where for<'a> &'a mut T: Send {}
133
134impl<T, R> Mutex<T, R> {
135    /// Creates a new [`Mutex`] wrapping the supplied data.
136    ///
137    /// # Example
138    ///
139    /// ```
140    /// use spin::Mutex;
141    ///
142    /// static MUTEX: Mutex<()> = Mutex::new(());
143    ///
144    /// fn demo() {
145    ///     let lock = MUTEX.lock();
146    ///     // do something with lock
147    ///     drop(lock);
148    /// }
149    /// ```
150    #[inline(always)]
151    pub const fn new(value: T) -> Self {
152        Self {
153            inner: InnerMutex::new(value),
154        }
155    }
156
157    /// Consumes this [`Mutex`] and unwraps the underlying data.
158    ///
159    /// # Example
160    ///
161    /// ```
162    /// let lock = spin::Mutex::new(42);
163    /// assert_eq!(42, lock.into_inner());
164    /// ```
165    #[inline(always)]
166    pub fn into_inner(self) -> T {
167        self.inner.into_inner()
168    }
169}
170
171impl<T: ?Sized, R: RelaxStrategy> Mutex<T, R> {
172    /// Locks the [`Mutex`] and returns a guard that permits access to the inner data.
173    ///
174    /// The returned value may be dereferenced for data access
175    /// and the lock will be dropped when the guard falls out of scope.
176    ///
177    /// ```
178    /// let lock = spin::Mutex::new(0);
179    /// {
180    ///     let mut data = lock.lock();
181    ///     // The lock is now locked and the data can be accessed
182    ///     *data += 1;
183    ///     // The lock is implicitly dropped at the end of the scope
184    /// }
185    /// ```
186    #[inline(always)]
187    pub fn lock(&self) -> MutexGuard<'_, T, R> {
188        MutexGuard {
189            inner: self.inner.lock(),
190        }
191    }
192}
193
194impl<T: ?Sized, R> Mutex<T, R> {
195    /// Returns `true` if the lock is currently held.
196    ///
197    /// # Safety
198    ///
199    /// This function provides no synchronization guarantees and so its result should be considered 'out of date'
200    /// the instant it is called. Do not use it for synchronization purposes. However, it may be useful as a heuristic.
201    #[inline(always)]
202    pub fn is_locked(&self) -> bool {
203        self.inner.is_locked()
204    }
205
206    /// Force unlock this [`Mutex`].
207    ///
208    /// # Safety
209    ///
210    /// This is *extremely* unsafe if the lock is not held by the current
211    /// thread. However, this can be useful in some instances for exposing the
212    /// lock to FFI that doesn't know how to deal with RAII.
213    #[inline(always)]
214    pub unsafe fn force_unlock(&self) {
215        self.inner.force_unlock()
216    }
217
218    /// Try to lock this [`Mutex`], returning a lock guard if successful.
219    ///
220    /// # Example
221    ///
222    /// ```
223    /// let lock = spin::Mutex::new(42);
224    ///
225    /// let maybe_guard = lock.try_lock();
226    /// assert!(maybe_guard.is_some());
227    ///
228    /// // `maybe_guard` is still held, so the second call fails
229    /// let maybe_guard2 = lock.try_lock();
230    /// assert!(maybe_guard2.is_none());
231    /// ```
232    #[inline(always)]
233    pub fn try_lock(&self) -> Option<MutexGuard<'_, T, R>> {
234        self.inner
235            .try_lock()
236            .map(|guard| MutexGuard { inner: guard })
237    }
238
239    /// Returns a mutable reference to the underlying data.
240    ///
241    /// Since this call borrows the [`Mutex`] mutably, and a mutable reference is guaranteed to be exclusive in Rust,
242    /// no actual locking needs to take place -- the mutable borrow statically guarantees no locks exist. As such,
243    /// this is a 'zero-cost' operation.
244    ///
245    /// # Example
246    ///
247    /// ```
248    /// let mut lock = spin::Mutex::new(0);
249    /// *lock.get_mut() = 10;
250    /// assert_eq!(*lock.lock(), 10);
251    /// ```
252    #[inline(always)]
253    pub fn get_mut(&mut self) -> &mut T {
254        self.inner.get_mut()
255    }
256}
257
258impl<T: ?Sized + fmt::Debug, R> fmt::Debug for Mutex<T, R> {
259    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260        fmt::Debug::fmt(&self.inner, f)
261    }
262}
263
264impl<T: Default, R> Default for Mutex<T, R> {
265    fn default() -> Self {
266        Self::new(Default::default())
267    }
268}
269
270impl<T, R> From<T> for Mutex<T, R> {
271    fn from(data: T) -> Self {
272        Self::new(data)
273    }
274}
275
276impl<'a, T: ?Sized, R> MutexGuard<'a, T, R> {
277    /// Leak the lock guard, yielding a mutable reference to the underlying data.
278    ///
279    /// Note that this function will permanently lock the original [`Mutex`].
280    ///
281    /// ```
282    /// let mylock = spin::Mutex::new(0);
283    ///
284    /// let data: &mut i32 = spin::MutexGuard::leak(mylock.lock());
285    ///
286    /// *data = 1;
287    /// assert_eq!(*data, 1);
288    /// ```
289    #[inline(always)]
290    pub fn leak(this: Self) -> &'a mut T {
291        InnerMutexGuard::leak(this.inner)
292    }
293}
294
295impl<'a, T: ?Sized + fmt::Debug, R> fmt::Debug for MutexGuard<'a, T, R> {
296    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
297        fmt::Debug::fmt(&**self, f)
298    }
299}
300
301impl<'a, T: ?Sized + fmt::Display, R> fmt::Display for MutexGuard<'a, T, R> {
302    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
303        fmt::Display::fmt(&**self, f)
304    }
305}
306
307impl<'a, T: ?Sized, R> Deref for MutexGuard<'a, T, R> {
308    type Target = T;
309    fn deref(&self) -> &T {
310        &self.inner
311    }
312}
313
314impl<'a, T: ?Sized, R> DerefMut for MutexGuard<'a, T, R> {
315    fn deref_mut(&mut self) -> &mut T {
316        &mut self.inner
317    }
318}
319
320#[cfg(feature = "lock_api")]
321unsafe impl<R: RelaxStrategy> lock_api_crate::RawMutex for Mutex<(), R> {
322    type GuardMarker = lock_api_crate::GuardSend;
323
324    const INIT: Self = Self::new(());
325
326    fn lock(&self) {
327        // Prevent guard destructor running
328        core::mem::forget(Self::lock(self));
329    }
330
331    fn try_lock(&self) -> bool {
332        // Prevent guard destructor running
333        Self::try_lock(self).map(core::mem::forget).is_some()
334    }
335
336    unsafe fn unlock(&self) {
337        self.force_unlock();
338    }
339
340    fn is_locked(&self) -> bool {
341        self.inner.is_locked()
342    }
343}