| 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<SpinMutex<WaitVariable<bool>>>, | |
| } | |
| // 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<WaitVariable<bool>> { | |
| 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 | |
| } | |
| } | |
| } |