use super::UPIntrFreeCell;
use alloc::collections::VecDeque;
use tg_task_manage::ThreadId;
pub trait Mutex: Sync + Send {
fn lock(&self, tid: ThreadId) -> bool;
fn unlock(&self) -> Option<ThreadId>;
}
pub struct MutexBlocking {
inner: UPIntrFreeCell<MutexBlockingInner>,
}
pub struct MutexBlockingInner {
locked: bool,
wait_queue: VecDeque<ThreadId>,
}
impl MutexBlocking {
pub fn new() -> Self {
Self {
inner: unsafe {
UPIntrFreeCell::new(MutexBlockingInner {
locked: false,
wait_queue: VecDeque::new(),
})
},
}
}
}
impl Mutex for MutexBlocking {
fn lock(&self, tid: ThreadId) -> bool {
let mut mutex_inner = self.inner.exclusive_access();
if mutex_inner.locked {
mutex_inner.wait_queue.push_back(tid);
drop(mutex_inner);
false
} else {
mutex_inner.locked = true;
true
}
}
fn unlock(&self) -> Option<ThreadId> {
let mut mutex_inner = self.inner.exclusive_access();
assert!(mutex_inner.locked);
if let Some(waking_task) = mutex_inner.wait_queue.pop_front() {
Some(waking_task)
} else {
mutex_inner.locked = false;
None
}
}
}