use crate::sys::pal::waitqueue::{SpinMutex, WaitQueue, WaitVariable, try_lock_or_false}; use crate::sys::sync::OnceBox; pub struct Mutex { // FIXME: `UnsafeList` is not movable. inner: OnceBox>>, } // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28 impl Mutex { pub const fn new() -> Mutex { Mutex { inner: OnceBox::new() } } fn get(&self) -> &SpinMutex> { self.inner.get_or_init(|| Box::pin(SpinMutex::new(WaitVariable::new(false)))).get_ref() } #[inline] pub fn lock(&self) { let mut guard = self.get().lock(); if *guard.lock_var() { // Another thread has the lock, wait WaitQueue::wait(guard, || {}) // Another thread has passed the lock to us } else { // We are just now obtaining the lock *guard.lock_var_mut() = true; } } #[inline] pub unsafe fn unlock(&self) { // SAFETY: the mutex was locked by the current thread, so it has been // initialized already. let guard = unsafe { self.inner.get_unchecked().get_ref().lock() }; if let Err(mut guard) = WaitQueue::notify_one(guard) { // No other waiters, unlock *guard.lock_var_mut() = false; } else { // There was a thread waiting, just pass the lock } } #[inline] pub fn try_lock(&self) -> bool { let mut guard = try_lock_or_false!(self.get()); if *guard.lock_var() { // Another thread has the lock false } else { // We are just now obtaining the lock *guard.lock_var_mut() = true; true } } }