1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
use crate::sys::mutex as sys;
use crate::sys_common::poison;
use std::cell::UnsafeCell;
use std::marker::PhantomPinned;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::ptr;
use std::sync::Arc;
use std::sync::LockResult;
use std::sync::PoisonError;
use std::sync::TryLockError;
use std::sync::TryLockResult;

/// A mutual exclusion primitive useful for protecting shared data
///
/// This mutex will block threads waiting for the lock to become available. The
/// mutex can also be statically initialized or created via a [`new`]
/// constructor. Each mutex has a type parameter which represents the data that
/// it is protecting. The data can only be accessed through the RAII guards
/// returned from [`lock`] and [`try_lock`], which guarantees that the data is only
/// ever accessed when the mutex is locked.
///
/// # Poisoning
///
/// The mutexes in this module implement a strategy called "poisoning" where a
/// mutex is considered poisoned whenever a thread panics while holding the
/// mutex. Once a mutex is poisoned, all other threads are unable to access the
/// data by default as it is likely tainted (some invariant is not being
/// upheld).
///
/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a
/// [`Result`] which indicates whether a mutex has been poisoned or not. Most
/// usage of a mutex will simply [`unwrap()`] these results, propagating panics
/// among threads to ensure that a possibly invalid invariant is not witnessed.
///
/// A poisoned mutex, however, does not prevent all access to the underlying
/// data. The [`PoisonError`] type has an [`into_inner`] method which will return
/// the guard that would have otherwise been returned on a successful lock. This
/// allows access to the data, despite the lock being poisoned.
///
/// [`new`]: Self::new
/// [`lock`]: Self::lock
/// [`try_lock`]: Self::try_lock
/// [`unwrap()`]: Result::unwrap
/// [`PoisonError`]: super::PoisonError
/// [`into_inner`]: super::PoisonError::into_inner
pub struct Mutex<T: ?Sized> {
    inner: sys::Mutex,
    poison: poison::Flag,
    _p: PhantomPinned,
    data: UnsafeCell<T>,
}

unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}

unsafe impl<T: ?Sized + Send + Sync> Sync for Mutex<T> {}

impl<T> Mutex<T> {
    /// Create a new, uninitialized mutex.
    ///
    /// This is *NOT* equivalent to `MaybeUninit::uninit().assume_init()`, which will cause
    /// undefined behaviour if used to create a new mutex.
    #[inline]
    pub const fn uninit(value: T) -> Self {
        Self {
            inner: sys::Mutex::uninit(),
            _p: PhantomPinned,
            poison: poison::Flag::new(),
            data: UnsafeCell::new(value),
        }
    }

    /// Create a new, initialized mutex.
    ///
    /// The resulting mutex is wrapped and ready for use.
    #[inline]
    pub fn boxed(value: T) -> Pin<Box<Self>> {
        let this = Box::pin(Self::uninit(value));
        this.as_ref().init();
        this
    }
    
    /// Create a new, initialized mutex.
    ///
    /// The resulting mutex is wrapped and ready for use.
    #[inline]
    pub fn arc(value: T) -> Pin<Arc<Self>> {
        let this = Arc::pin(Self::uninit(value));
        this.as_ref().init();
        this
    }
}

impl<T: ?Sized> Mutex<T> {
    /// Initialize a mutex, making it ready for use.
    ///
    /// # Panics
    ///
    /// This function may panic if the mutex was already initialized.
    #[inline]
    pub fn init(self: Pin<&Self>) {
        self.inner().init()
    }

    /// Acquires a mutex, blocking the current thread until it is able to do so.
    ///
    /// This function will block the local thread until it is available to acquire
    /// the mutex. Upon returning, the thread is the only thread with the lock
    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
    /// the guard goes out of scope, the mutex will be unlocked.
    ///
    /// The exact behavior on locking a mutex in the thread which already holds
    /// the lock is left unspecified. However, this function will not return on
    /// the second call (it might panic or deadlock, for example).
    ///
    /// # Errors
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return an error once the mutex is acquired.
    ///
    /// # Panics
    ///
    /// This function might panic when called if the lock is already held by the
    /// current thread.
    ///
    /// This function may panic if the mutex is not initialized.
    #[inline]
    pub fn lock(self: Pin<&Self>) -> LockResult<MutexGuard<T>> {
        let guard = self.inner().lock();
        poison::map_result(self.poison.borrow(), |poison| MutexGuard {
            guard,
            mutex: self,
            poison,
        })
    }

    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then [`Err`] is returned.
    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
    /// guard is dropped.
    ///
    /// This function does not block.
    ///
    /// # Errors
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return an error if the mutex would otherwise be
    /// acquired.
    ///
    /// # Panics
    ///
    /// This function may panic if the mutex is not initialized.
    #[inline]
    pub fn try_lock(self: Pin<&Self>) -> TryLockResult<MutexGuard<T>> {
        let guard = self.inner().try_lock().ok_or(TryLockError::WouldBlock)?;
        Ok(poison::map_result(self.poison.borrow(), |poison| {
            MutexGuard {
                guard,
                mutex: self,
                poison,
            }
        })?)
    }

    /// Determines whether the mutex is poisoned.
    ///
    /// If another thread is active, the mutex can still become poisoned at any
    /// time. You should not trust a `false` value for program correctness
    /// without additional synchronization.
    #[inline]
    pub fn is_poisoned(self: Pin<&Self>) -> bool {
        self.poison.get()
    }

    /// Consumes this mutex, returning the underlying data.
    ///
    /// # Errors
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return an error instead.
    pub fn into_inner(self) -> LockResult<T>
    where
        T: Sized,
    {
        let Self { data, poison, .. } = self;
        poison::map_result(poison.borrow(), |_| data.into_inner())
    }

    /// Returns a mutable reference to the underlying data.
    ///
    /// Since this call borrows the `Mutex` mutably, no actual locking needs to
    /// take place -- the mutable borrow statically guarantees no locks exist.
    ///
    /// # Errors
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return an error instead.
    pub fn get_mut(&mut self) -> LockResult<&mut T> {
        let data = self.data.get_mut();
        poison::map_result(self.poison.borrow(), |_| data)
    }

    #[inline]
    fn inner(self: Pin<&Self>) -> Pin<&sys::Mutex> {
        unsafe { self.map_unchecked(|this| &this.inner) }
    }
}

pub struct MutexGuard<'a, T: ?Sized> {
    // This is suboptimal but necessary for `fallback` as `sync::Mutex` does not provide raw
    // unlocking.
    guard: sys::MutexGuard<'a>,
    mutex: Pin<&'a Mutex<T>>,
    poison: poison::Guard,
}

unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}

impl<'a, T: ?Sized> MutexGuard<'a, T> {
    #[inline]
    pub(crate) fn map(self, f: impl FnOnce(sys::MutexGuard<'a>) -> sys::MutexGuard<'a>) -> LockResult<Self> {
        let (guard, mutex, poison) = unsafe {
            let guard = ptr::read(&self.guard);
            let mutex = ptr::read(&self.mutex);
            let poison = ptr::read(&self.poison);
            mem::forget(self);
            (guard, mutex, poison)
        };

        let guard = f(guard);

        Self {
            guard,
            mutex,
            poison,
        }.repoison()
    }

    #[inline]
    fn repoison(self) -> LockResult<Self> {
        if self.mutex.is_poisoned() {
            Err(PoisonError::new(self))
        } else {
            Ok(self)
        }
    }
}

impl<T: ?Sized> Deref for MutexGuard<'_, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        unsafe { &*self.mutex.data.get() }
    }
}

impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.mutex.data.get() }
    }
}

impl<T: ?Sized> Drop for MutexGuard<'_, T> {
    #[inline]
    fn drop(&mut self) {
        self.mutex.poison.done(&self.poison);
    }
}