1use super::UPIntrFreeCell;
2use alloc::collections::VecDeque;
3use tg_task_manage::ThreadId;
4
5pub trait Mutex: Sync + Send {
7 fn lock(&self, tid: ThreadId) -> bool;
9 fn unlock(&self) -> Option<ThreadId>;
11}
12
13pub struct MutexBlocking {
15 inner: UPIntrFreeCell<MutexBlockingInner>,
16}
17
18pub struct MutexBlockingInner {
20 locked: bool,
21 wait_queue: VecDeque<ThreadId>,
22}
23
24impl MutexBlocking {
25 pub fn new() -> Self {
27 Self {
28 inner: unsafe {
30 UPIntrFreeCell::new(MutexBlockingInner {
31 locked: false,
32 wait_queue: VecDeque::new(),
33 })
34 },
35 }
36 }
37}
38
39impl Mutex for MutexBlocking {
40 fn lock(&self, tid: ThreadId) -> bool {
42 let mut mutex_inner = self.inner.exclusive_access();
43 if mutex_inner.locked {
44 mutex_inner.wait_queue.push_back(tid);
45 drop(mutex_inner);
46 false
47 } else {
48 mutex_inner.locked = true;
49 true
50 }
51 }
52 fn unlock(&self) -> Option<ThreadId> {
54 let mut mutex_inner = self.inner.exclusive_access();
55 assert!(mutex_inner.locked);
56 if let Some(waking_task) = mutex_inner.wait_queue.pop_front() {
57 Some(waking_task)
58 } else {
59 mutex_inner.locked = false;
60 None
61 }
62 }
63}