blob: 0dbf020ebe06af53bd12e53de14d655aa89001a4 [file] [log] [blame]
use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable};
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
/// FIXME: `UnsafeList` is not movable.
struct AllocatedMutex(SpinMutex<WaitVariable<bool>>);
pub struct Mutex {
inner: LazyBox<AllocatedMutex>,
}
impl LazyInit for AllocatedMutex {
fn init() -> Box<Self> {
Box::new(AllocatedMutex(SpinMutex::new(WaitVariable::new(false))))
}
}
// Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
impl Mutex {
pub const fn new() -> Mutex {
Mutex { inner: LazyBox::new() }
}
#[inline]
pub fn lock(&self) {
let mut guard = self.inner.0.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) {
let guard = self.inner.0.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.inner.0);
if *guard.lock_var() {
// Another thread has the lock
false
} else {
// We are just now obtaining the lock
*guard.lock_var_mut() = true;
true
}
}
}