spin_sync/
mutex.rs

1// Copyright 2020 Shin Yoshida
2//
3// "LGPL-3.0-or-later OR Apache-2.0 OR BSD-2-Clause"
4//
5// This is part of spin-sync
6//
7//  spin-sync is free software: you can redistribute it and/or modify
8//  it under the terms of the GNU Lesser General Public License as published by
9//  the Free Software Foundation, either version 3 of the License, or
10//  (at your option) any later version.
11//
12//  spin-sync is distributed in the hope that it will be useful,
13//  but WITHOUT ANY WARRANTY; without even the implied warranty of
14//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15//  GNU Lesser General Public License for more details.
16//
17//  You should have received a copy of the GNU Lesser General Public License
18//  along with spin-sync.  If not, see <http://www.gnu.org/licenses/>.
19//
20//
21// Licensed under the Apache License, Version 2.0 (the "License");
22// you may not use this file except in compliance with the License.
23// You may obtain a copy of the License at
24//
25//     http://www.apache.org/licenses/LICENSE-2.0
26//
27// Unless required by applicable law or agreed to in writing, software
28// distributed under the License is distributed on an "AS IS" BASIS,
29// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30// See the License for the specific language governing permissions and
31// limitations under the License.
32//
33//
34// Redistribution and use in source and binary forms, with or without modification, are permitted
35// provided that the following conditions are met:
36//
37// 1. Redistributions of source code must retain the above copyright notice, this list of
38//    conditions and the following disclaimer.
39// 2. Redistributions in binary form must reproduce the above copyright notice, this
40//    list of conditions and the following disclaimer in the documentation and/or other
41//    materials provided with the distribution.
42//
43// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
44// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
46// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
47// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
48// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
49// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
50// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
52// POSSIBILITY OF SUCH DAMAGE.
53
54use std::cell::UnsafeCell;
55use std::fmt;
56use std::ops::{Deref, DerefMut};
57use std::panic::{RefUnwindSafe, UnwindSafe};
58use std::sync::atomic::{AtomicU8, Ordering};
59
60use crate::misc::{PhantomMutex, PhantomMutexGuard};
61use crate::result::{LockResult, PoisonError, TryLockError, TryLockResult};
62
63/// A mutual exclusion primitive useful for protecting shared data.
64///
65/// It behaves like std::sync::Mutex except for using spinlock.
66/// What is more, the constructor is a const function; i.e. it is possible to declare
67/// static Mutex<T> variable as long as the inner data can be built statically.
68///
69/// This mutex will block threads waiting for the lock to become available. The
70/// mutex can also be statically initialized or created via a [`new`]
71/// constructor. Each mutex has a type parameter which represents the data that
72/// it is protecting. The data can only be accessed through the RAII guards
73/// returned from [`lock`] and [`try_lock`], which guarantees that the data is only
74/// ever accessed when the mutex is locked.
75///
76/// # Poisoning
77///
78/// The mutexes in this module implement a strategy called "poisoning" where a
79/// mutex is considered poisoned whenever a thread panics while holding the
80/// mutex. Once a mutex is poisoned, all other threads are unable to access the
81/// data by default as it is likely tainted.
82///
83/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a
84/// `Result` which indicates whether a mutex has been poisoned or not. Most
85/// usage of a mutex will simply `unwrap()` these results, propagating panics
86/// among threads to ensure that a possibly invalid invariant is not witnessed.
87///
88/// A poisoned mutex, however, does not prevent all access to the underlying
89/// data. The [`PoisonError`] type has an `into_inner` method which will return
90/// the guard that would have otherwise been returned on a successful lock. This
91/// allows access to the data, despite the lock being poisoned.
92///
93/// [`new`]: #method.new
94/// [`lock`]: #method.lock
95/// [`try_lock`]: #method.try_lock
96/// [`PoisonError`]: type.PoisonError.html
97///
98/// # Examples
99///
100/// Protect a variable (non-atomically) and update it in worker threads.
101///
102/// ```
103/// use spin_sync::Mutex;
104/// use std::thread;
105///
106/// const WORKER_NUM: usize = 10;
107///
108/// // We can declare static Mutex<usize> variable because Mutex::new is const.
109/// static MUTEX: Mutex<usize> = Mutex::new(0);
110///
111/// let mut handles = Vec::with_capacity(WORKER_NUM);
112///
113/// // Create worker threads to inclement the value by 1.
114/// for _ in 0..WORKER_NUM {
115///     let handle = thread::spawn(move || {
116///         let mut num = MUTEX.lock().unwrap();
117///         *num += 1;
118///     });
119///
120///     handles.push(handle);
121/// }
122///
123/// // Wait for the all worker threads are finished.
124/// for handle in handles {
125///     handle.join().unwrap();
126/// }
127///
128/// // Make sure the value is incremented by the worker count.
129/// let num = MUTEX.lock().unwrap();
130/// assert_eq!(WORKER_NUM, *num);
131/// ```
132///
133/// To recover from a poisoned mutex:
134///
135/// ```
136/// use spin_sync::Mutex;
137/// use std::sync::Arc;
138/// use std::thread;
139///
140/// // Like std::sync::Mutex, it can be declare as local variable, of course.
141/// let mutex = Arc::new(Mutex::new(0));
142/// let c_mutex = mutex.clone();
143///
144/// let _ = thread::spawn(move || -> () {
145///     // This thread will acquire the mutex first, unwrapping the result of
146///     // `lock` because the lock has not been poisoned.
147///     let _guard = c_mutex.lock().unwrap();
148///
149///     // This panic while holding the lock (`_guard` is in scope) will poison
150///     // the mutex.
151///     panic!();
152/// }).join();
153///
154/// // Here, the mutex has been poisoned.
155/// assert_eq!(true, mutex.is_poisoned());
156///
157/// // The returned result can be pattern matched on to return the underlying
158/// // guard on both branches.
159/// let mut guard = match mutex.lock() {
160///     Ok(guard) => guard,
161///     Err(poisoned) => poisoned.into_inner(),
162/// };
163///
164/// *guard += 1;
165/// assert_eq!(1, *guard);
166/// ```
167pub struct Mutex<T: ?Sized> {
168    lock: AtomicU8,
169    _phantom: PhantomMutex<T>,
170    data: UnsafeCell<T>,
171}
172
173impl<T> Mutex<T> {
174    /// Creates a new mutex in an unlocked state ready for use.
175    ///
176    /// unlike to `std::sync::Mutex::new`, this is a const function.
177    /// It can be use for static variable.
178    ///
179    /// # Examples
180    ///
181    /// Declare as a static variable.
182    ///
183    /// ```
184    /// use spin_sync::Mutex;
185    ///
186    /// static MUTEX: Mutex<i32> = Mutex::new(0);
187    /// ```
188    ///
189    /// Declare as a local variable.
190    ///
191    /// ```
192    /// use spin_sync::Mutex;
193    ///
194    /// let mutex = Mutex::new(0);
195    /// ```
196    pub const fn new(t: T) -> Self {
197        Mutex {
198            lock: AtomicU8::new(INIT),
199            data: UnsafeCell::new(t),
200            _phantom: PhantomMutex {},
201        }
202    }
203
204    /// Consumes this mutex and returns the underlying data.
205    ///
206    /// Note that this method won't acquire any lock because we know there is
207    /// no other references to `self`.
208    ///
209    /// # Errors
210    ///
211    /// If another user panicked while holding this mutex, this call wraps
212    /// the result in an error and returns it.
213    ///
214    /// # Examples
215    ///
216    /// ```
217    /// use spin_sync::Mutex;
218    ///
219    /// let mutex = Mutex::new(0);
220    /// assert_eq!(0, mutex.into_inner().unwrap());
221    /// ```
222    pub fn into_inner(self) -> LockResult<T> {
223        let is_err = self.is_poisoned();
224        let data = self.data.into_inner();
225
226        if is_err {
227            Err(PoisonError::new(data))
228        } else {
229            Ok(data)
230        }
231    }
232}
233
234impl<T: ?Sized> Mutex<T> {
235    /// Blocks the current thread until acquiring the lock, and returns an RAII guard object.
236    ///
237    /// The actual flow will be as follows.
238    ///
239    /// 1. User calls this method.
240    ///    1. Blocks until this thread acquires the exclusive lock.
241    ///    1. Creates an RAII guard object.
242    ///    1. Wraps the guard in `Result` and returns it. If this mutex has been
243    ///       poisoned, it is wrapped in an `Err`; otherwise wrapped in a `Ok`.
244    /// 1. User accesses to the underlying data through the returned guard.
245    ///    (No other thread can access to the data then.)
246    /// 1. The guard is dropped (falls out of scope) and the lock is released.
247    ///
248    /// # Errors
249    ///
250    /// If another user panicked while holding this mutex, this method call wraps
251    /// the guard in an error and returns it.
252    ///
253    /// # Examples
254    ///
255    /// ```
256    /// use spin_sync::Mutex;
257    ///
258    /// let mutex = Mutex::new(0);
259    ///
260    /// let mut guard = mutex.lock().unwrap();
261    /// assert_eq!(0, *guard);
262    ///
263    /// *guard += 1;
264    /// assert_eq!(1, *guard);
265    ///
266    /// assert_eq!(true, mutex.try_lock().is_err());
267    /// ```
268    pub fn lock(&self) -> LockResult<MutexGuard<T>> {
269        loop {
270            match self.do_try_lock() {
271                s if is_locked(s) => std::thread::yield_now(),
272                s if is_poisoned(s) => return Err(PoisonError::new(MutexGuard::new(self))),
273                _ => return Ok(MutexGuard::new(self)),
274            }
275        }
276    }
277
278    /// Attempts to acquire this lock and returns an RAII guard object if succeeded.
279    ///
280    /// Behaves like [`lock`] except for this method returns an error immediately if another
281    /// user is holding the lock.
282    ///
283    /// This method does not block.
284    ///
285    /// The actual flow will be as follows.
286    ///
287    /// 1. User calls this method.
288    ///    1. Tries to acquire the lock. If failed (i.e. if the lock is being held,)
289    ///       returns an error immediately and this flow is finished here.
290    ///    1. Creates an RAII guard object.
291    ///    1. Wrapps the guard in `Result` and returns it. If this mutex has been
292    ///       poisoned, it is wrapped in an `Err`; otherwise wrapped in an `Ok`.
293    /// 1. User accesses to the underlying data through the returned guard.
294    ///    (No other thread can access to the data then.)
295    /// 1. The guard is dropped (falls out of scope) and the lock is released.
296    ///
297    /// # Errors
298    ///
299    /// - If another user is holding this mutex, [`TryLockError::WouldBlock`] is returned.
300    /// - If this function call succeeded to acquire the lock, and if another
301    ///   user panicked while holding this mutex, [`TryLockError::Poisoned`] is returned.
302    ///
303    /// [`lock`]: #method.lock
304    /// [`TryLockError::WouldBlock`]: type.TryLockError.html
305    /// [`TryLockError::Poisoned`]: type.TryLockError.html
306    ///
307    /// # Examples
308    ///
309    /// ```
310    /// use spin_sync::Mutex;
311    ///
312    /// let mutex = Mutex::new(0);
313    ///
314    /// // try_lock() fails while another guard is.
315    /// // It doesn't cause a deadlock.
316    /// {
317    ///     let _guard = mutex.lock().unwrap();
318    ///     assert_eq!(true, mutex.try_lock().is_err());
319    /// }
320    ///
321    /// // try_lock() behaves like lock() if no other guard is.
322    /// {
323    ///     let mut guard = mutex.try_lock().unwrap();
324    ///     assert_eq!(true, mutex.try_lock().is_err());
325    ///     *guard += 1;
326    /// }
327    ///
328    /// let guard = mutex.try_lock().unwrap();
329    /// assert_eq!(1, *guard);
330    /// ```
331    pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> {
332        match self.do_try_lock() {
333            s if is_locked(s) => Err(TryLockError::WouldBlock),
334            s if is_poisoned(s) => Err(TryLockError::Poisoned(PoisonError::new(MutexGuard::new(
335                self,
336            )))),
337            _ => Ok(MutexGuard::new(self)),
338        }
339    }
340
341    /// Tries to acquire lock and returns the lock status before updated.
342    fn do_try_lock(&self) -> LockStatus {
343        // Assume neither poisoned nor locked at first.
344        let mut expected = INIT;
345
346        loop {
347            let desired = acquire_lock(expected);
348            match self
349                .lock
350                .compare_and_swap(expected, desired, Ordering::Acquire)
351            {
352                s if s == expected => return s, // Succeeded
353                s if is_locked(s) => return s,  // Another user is holding the lock.
354                s => expected = s,              // Assumption was wrong. Try again.
355            }
356        }
357    }
358
359    /// Determines whether the mutex is poisoned or not.
360    ///
361    /// # Warnings
362    ///
363    /// This function won't acquire any lock. If another thread is active,
364    /// the mutex can become poisoned at any time. You should not trust a `false`
365    /// value for program correctness without additional synchronization.
366    ///
367    /// This behavior is same to `std::sync::Mutex::is_poisoned()`.
368    ///
369    /// # Examples
370    ///
371    /// ```
372    /// use spin_sync::Mutex;
373    /// use std::sync::Arc;
374    /// use std::thread;
375    ///
376    /// let mutex = Arc::new(Mutex::new(0));
377    /// assert_eq!(false, mutex.is_poisoned());
378    ///
379    /// // Panic and poison the mutex.
380    /// {
381    ///     let mutex = mutex.clone();
382    ///
383    ///     let _ = thread::spawn(move || {
384    ///         // This panic while holding the lock (`_guard` is in scope) will poison
385    ///         // the mutex.
386    ///         let _guard = mutex.lock().unwrap();
387    ///         panic!("Poison here");
388    ///     }).join();
389    /// }
390    ///
391    /// assert_eq!(true, mutex.is_poisoned());
392    /// ```
393    pub fn is_poisoned(&self) -> bool {
394        // Don't acquire any lock; otherwise, this function will cause
395        // a deadlock if the caller thread is holding the lock.
396        let status = self.lock.load(Ordering::Relaxed);
397        return is_poisoned(status);
398    }
399
400    /// Returns a mutable reference to the underlying data.
401    ///
402    /// Note that this method won't acquire any lock because we know there is
403    /// no other references to `self`.
404    ///
405    /// # Errors
406    ///
407    /// If another user panicked while holding this mutex, this method call
408    /// wraps the result in an error and returns it.
409    ///
410    /// # Examples
411    ///
412    /// ```
413    /// use spin_sync::Mutex;
414    ///
415    /// let mut mutex = Mutex::new(0);
416    /// *mutex.get_mut().unwrap() = 10;
417    /// assert_eq!(10, *mutex.lock().unwrap());
418    /// ```
419    pub fn get_mut(&mut self) -> LockResult<&mut T> {
420        // There is no other references to `self` because the argument is
421        // a mutable reference.
422        // No lock is required.
423        let data = unsafe { &mut *self.data.get() };
424
425        if self.is_poisoned() {
426            Err(PoisonError::new(data))
427        } else {
428            Ok(data)
429        }
430    }
431}
432
433impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
434    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435        match self.try_lock() {
436            Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
437            Err(TryLockError::Poisoned(err)) => f
438                .debug_struct("Mutex")
439                .field("data", &&**err.get_ref())
440                .finish(),
441            Err(TryLockError::WouldBlock) => {
442                struct LockedPlaceholder;
443                impl fmt::Debug for LockedPlaceholder {
444                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
445                        f.write_str("<locked>")
446                    }
447                }
448
449                f.debug_struct("Mutex")
450                    .field("data", &LockedPlaceholder)
451                    .finish()
452            }
453        }
454    }
455}
456
457impl<T> From<T> for Mutex<T> {
458    fn from(t: T) -> Self {
459        Mutex::new(t)
460    }
461}
462
463impl<T: ?Sized + Default> Default for Mutex<T> {
464    fn default() -> Self {
465        Mutex::new(T::default())
466    }
467}
468
469/// An RAII implementation of a "scoped lock" of a mutex.
470///
471/// When this structure is dropped (falls out of scope), the lock will be released.
472///
473/// The data protected by the mutex can be accessed through this guard via its
474/// `Deref` and `DerefMut` implementations.
475///
476/// This structure is created by [`lock`] and [`try_lock`] methods on
477/// [`Mutex`].
478///
479/// [`lock`]: struct.Mutex.html#method.lock
480/// [`try_lock`]: struct.Mutex.html#method.try_lock
481/// [`Mutex`]: struct.Mutex.html
482#[must_use = "if unused the Mutex will immediately unlock"]
483pub struct MutexGuard<'a, T: ?Sized + 'a> {
484    mutex: &'a Mutex<T>,
485    _phantom: PhantomMutexGuard<'a, T>, // To implement !Send.
486}
487
488impl<'a, T: ?Sized> MutexGuard<'a, T> {
489    fn new(mutex: &'a Mutex<T>) -> Self {
490        Self {
491            mutex,
492            _phantom: Default::default(),
493        }
494    }
495}
496
497impl<T: ?Sized> Drop for MutexGuard<'_, T> {
498    fn drop(&mut self) {
499        let old_status = self.mutex.lock.load(Ordering::Relaxed);
500        debug_assert!(is_locked(old_status));
501
502        let mut new_status = release_lock(old_status);
503        if std::thread::panicking() {
504            new_status = set_poison_flag(new_status);
505        }
506
507        self.mutex.lock.store(new_status, Ordering::Release);
508    }
509}
510
511impl<T: ?Sized> Deref for MutexGuard<'_, T> {
512    type Target = T;
513
514    fn deref(&self) -> &Self::Target {
515        unsafe { &*self.mutex.data.get() }
516    }
517}
518
519impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
520    fn deref_mut(&mut self) -> &mut Self::Target {
521        unsafe { &mut *self.mutex.data.get() }
522    }
523}
524
525impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
526    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527        fmt::Debug::fmt(&**self, f)
528    }
529}
530
531impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
532    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533        fmt::Display::fmt(&**self, f)
534    }
535}
536
537//
538// Marker Traits
539//
540
541impl<T: ?Sized> UnwindSafe for Mutex<T> {}
542impl<T: ?Sized> RefUnwindSafe for Mutex<T> {}
543
544unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
545unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
546
547unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
548
549//
550// Constants to represent lock state
551//
552type LockStatus = u8;
553
554const INIT: LockStatus = 0;
555const LOCK_FLAG: LockStatus = 0x01;
556const POISON_FLAG: LockStatus = 0x02;
557const NOT_USED_MASK: LockStatus = 0xfc;
558
559#[inline]
560#[must_use]
561fn is_locked(s: LockStatus) -> bool {
562    debug_assert_eq!(0, s & NOT_USED_MASK);
563    (s & LOCK_FLAG) != 0
564}
565
566#[inline]
567#[must_use]
568fn acquire_lock(s: LockStatus) -> LockStatus {
569    debug_assert_eq!(false, is_locked(s));
570    s | LOCK_FLAG
571}
572
573#[inline]
574#[must_use]
575fn release_lock(s: LockStatus) -> LockStatus {
576    debug_assert_eq!(true, is_locked(s));
577    s & !(LOCK_FLAG)
578}
579
580#[inline]
581#[must_use]
582fn is_poisoned(s: LockStatus) -> bool {
583    debug_assert_eq!(0, s & NOT_USED_MASK);
584    (s & POISON_FLAG) != 0
585}
586
587#[inline]
588#[must_use]
589fn set_poison_flag(s: LockStatus) -> LockStatus {
590    debug_assert_eq!(0, s & NOT_USED_MASK);
591    s | POISON_FLAG
592}