1use core::{
6 marker::PhantomData,
7 ops::{Deref, DerefMut},
8 sync::atomic::{AtomicU32, Ordering},
9 time::Duration,
10};
11
12use crate::syscalls::futex::{futex_wait, futex_wake};
13
14const M_AVAILABLE: u32 = 0;
15const M_LOCKED: u32 = 1;
16const M_WAITED_ON: u32 = 2;
17
18#[must_use = "if unused the Mutex will immediately unlock"]
19pub struct MutexGuard<'a, T> {
20 mutex: &'a Mutex<T>,
21 marker: PhantomData<&'a mut T>,
22}
23
24impl<'a, T> Drop for MutexGuard<'a, T> {
25 fn drop(&mut self) {
26 unsafe {
27 self.mutex.force_unlock();
28 }
29 }
30}
31
32impl<'a, T> Deref for MutexGuard<'a, T> {
33 type Target = T;
34
35 fn deref(&self) -> &Self::Target {
36 unsafe { &*self.mutex.get() }
37 }
38}
39
40impl<'a, T> DerefMut for MutexGuard<'a, T> {
41 fn deref_mut(&mut self) -> &mut Self::Target {
42 unsafe { &mut *self.mutex.get() }
43 }
44}
45
46#[derive(Debug)]
47pub struct Mutex<T> {
48 state: AtomicU32,
49 inner: T,
50}
51
52impl<T> Mutex<T> {
53 pub const fn new(inner: T) -> Self {
55 Self {
56 state: AtomicU32::new(M_AVAILABLE),
57 inner,
58 }
59 }
60 pub const fn get_mut(&mut self) -> &mut T {
62 &mut self.inner
63 }
64 pub const fn get(&self) -> *mut T {
66 &self.inner as *const T as *mut T
67 }
68 pub fn lock(&self) -> MutexGuard<'_, T> {
72 if let Err(mut s) = self.state.compare_exchange_weak(
73 M_AVAILABLE,
74 M_LOCKED,
75 Ordering::Acquire,
76 Ordering::Relaxed,
77 ) {
78 if s != M_WAITED_ON {
79 s = self.state.swap(M_WAITED_ON, Ordering::Acquire);
80 }
81
82 while s != M_AVAILABLE {
83 futex_wait(&self.state, M_WAITED_ON, Duration::MAX)
84 .expect("System error while waiting for a Futex");
85
86 s = self.state.swap(M_WAITED_ON, Ordering::Acquire);
87 }
88 }
89 MutexGuard {
90 mutex: self,
91 marker: PhantomData,
92 }
93 }
94 pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
96 if self
97 .state
98 .compare_exchange(
99 M_AVAILABLE,
100 M_LOCKED,
101 core::sync::atomic::Ordering::Acquire,
102 core::sync::atomic::Ordering::Relaxed,
103 )
104 .is_ok()
105 {
106 Some(MutexGuard {
107 mutex: self,
108 marker: PhantomData,
109 })
110 } else {
111 None
112 }
113 }
114 pub unsafe fn force_unlock(&self) {
116 if self.state.fetch_sub(1, Ordering::Acquire) != M_LOCKED {
117 self.state.store(M_AVAILABLE, Ordering::Release);
119 futex_wake(&self.state, 1).expect("System error while waking 1 Futex");
120 }
121 }
122}
123
124impl<T: Clone> Clone for Mutex<T> {
125 fn clone(&self) -> Self {
126 Mutex {
127 state: AtomicU32::new(M_AVAILABLE),
128 inner: self.inner.clone(),
129 }
130 }
131}