use crate::ctx::*;
use crate::ptr::*;
use crate::scheduler::*;
struct MutexInner {
pub(crate) owner: Ptr<Context>,
pub(crate) wait_queue: std::collections::LinkedList<crate::ptr::Ptr<Context>>,
}
#[derive(Clone, PartialEq, Eq)]
pub struct Mutex {
inner: Ptr<MutexInner>,
}
impl Drop for Mutex {
fn drop(&mut self) {
unsafe {
std::intrinsics::drop_in_place(self.inner.0);
}
}
}
impl Mutex {
pub fn new() -> Self {
Self {
inner: Ptr::new(MutexInner {
owner: Ptr::null(),
wait_queue: std::collections::LinkedList::new(),
}),
}
}
pub fn lock(&self) {
let inner = self.inner.get();
loop {
let active_ctx = RUNTIME.with(|rt| rt.get().active_ctx);
if active_ctx == inner.owner {
panic!("greenie: deadlock detected");
} else if inner.owner.is_null() {
inner.owner = active_ctx;
return;
}
inner.wait_queue.push_back(active_ctx);
RUNTIME.with(|rt| {
rt.get().suspend_thread(rt.active_ctx);
rt.get().yield_();
});
}
}
pub fn try_lock(&self) -> bool {
let active_ctx = RUNTIME.with(|rt| rt.get().active_ctx);
let inner = self.inner.get();
if active_ctx == inner.owner {
panic!("greenie: deadlock detected");
} else if inner.owner.is_null() {
inner.owner = active_ctx;
}
yield_thread();
active_ctx == inner.owner
}
pub fn unlock(&self) {
let inner = self.inner.get();
let active_ctx = RUNTIME.with(|rt| rt.get().active_ctx);
if active_ctx != inner.owner {
panic!("greenie: no privilege to perform the operation");
}
inner.owner = Ptr::null();
if !inner.wait_queue.is_empty() {
let ctx = inner.wait_queue.pop_front().unwrap();
Context::resume(ctx);
}
}
}