1use core::sync::atomic::{AtomicU64, Ordering};
4
5use arceos_api::task::{self as api, AxWaitQueueHandle};
6
7pub struct RawMutex {
13 wq: AxWaitQueueHandle,
14 owner_id: AtomicU64,
15}
16
17impl RawMutex {
18 #[inline(always)]
20 pub const fn new() -> Self {
21 Self {
22 wq: AxWaitQueueHandle::new(),
23 owner_id: AtomicU64::new(0),
24 }
25 }
26}
27
28unsafe impl lock_api::RawMutex for RawMutex {
29 const INIT: Self = RawMutex::new();
30
31 type GuardMarker = lock_api::GuardSend;
32
33 #[inline(always)]
34 fn lock(&self) {
35 let current_id = api::ax_current_task_id();
36 loop {
37 match self.owner_id.compare_exchange_weak(
40 0,
41 current_id,
42 Ordering::Acquire,
43 Ordering::Relaxed,
44 ) {
45 Ok(_) => break,
46 Err(owner_id) => {
47 assert_ne!(
48 owner_id, current_id,
49 "Thread({current_id}) tried to acquire mutex it already owns.",
50 );
51 api::ax_wait_queue_wait_until(&self.wq, || !self.is_locked(), None);
53 }
54 }
55 }
56 }
57
58 #[inline(always)]
59 fn try_lock(&self) -> bool {
60 let current_id = api::ax_current_task_id();
61 self.owner_id
64 .compare_exchange(0, current_id, Ordering::Acquire, Ordering::Relaxed)
65 .is_ok()
66 }
67
68 #[inline(always)]
69 unsafe fn unlock(&self) {
70 let owner_id = self.owner_id.swap(0, Ordering::Release);
71 let current_id = api::ax_current_task_id();
72 assert_eq!(
73 owner_id, current_id,
74 "Thread({current_id}) tried to release mutex it doesn't own",
75 );
76 api::ax_wait_queue_wake(&self.wq, 1);
78 }
79
80 #[inline(always)]
81 fn is_locked(&self) -> bool {
82 self.owner_id.load(Ordering::Relaxed) != 0
83 }
84}
85
86pub type Mutex<T> = lock_api::Mutex<RawMutex, T>;
88pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>;