abi/task/
mutex.rs

1use core::{
2    mem::{align_of, size_of},
3    ptr::drop_in_place,
4};
5use synchronization::blocking_mutex::{Mutex, raw::CriticalSectionRawMutex};
6
7use crate::context;
8
9#[derive(Debug, Clone, Copy, Default)]
10struct MutexState {
11    task: Option<usize>,
12    lock_count: u32, // For recursive mutexes
13}
14
15pub struct RawMutex {
16    mutex: Mutex<CriticalSectionRawMutex, MutexState>,
17    recursive: bool,
18}
19
20impl RawMutex {
21    pub fn new(recursive: bool) -> Self {
22        Self {
23            mutex: Mutex::new(MutexState::default()),
24            recursive,
25        }
26    }
27
28    pub fn is_valid_pointer(pointer: *const RawMutex) -> bool {
29        !pointer.is_null() && (pointer as usize).is_multiple_of(align_of::<Self>())
30    }
31
32    /// Transforms a pointer to a reference.
33    ///
34    /// # Safety
35    ///
36    /// This function is unsafe because it dereferences a raw pointer.
37    /// The caller must ensure the pointer is valid and points to properly initialized memory.
38    pub unsafe fn from_pointer<'a>(pointer: *const RawMutex) -> Option<&'a Self> {
39        unsafe {
40            if !Self::is_valid_pointer(pointer) {
41                return None;
42            }
43            Some(&*pointer)
44        }
45    }
46
47    /// Transforms a mutable pointer to a mutable reference.
48    ///
49    /// # Safety
50    ///
51    /// This function is unsafe because it dereferences a raw pointer.
52    /// The caller must ensure the pointer is valid and points to properly initialized memory.
53    pub unsafe fn from_mutable_pointer<'a>(pointer: *mut RawMutex) -> Option<&'a mut Self> {
54        unsafe {
55            if !Self::is_valid_pointer(pointer) {
56                return None;
57            }
58            Some(&mut *pointer)
59        }
60    }
61
62    pub fn lock(&self) -> bool {
63        let current_task = context::get_instance()
64            .get_current_task_identifier()
65            .into_inner() as usize;
66
67        unsafe {
68            self.mutex.lock_mut(|state| {
69                if let Some(owner) = state.task {
70                    if owner == current_task && self.recursive {
71                        // Recursive lock
72                        state.lock_count += 1;
73                        return true;
74                    }
75                    // Mutex is already locked by another task
76                    return false;
77                }
78
79                // Lock is available
80                state.task = Some(current_task);
81                state.lock_count = 1;
82                true
83            })
84        }
85    }
86
87    pub fn unlock(&self) -> bool {
88        let current_task = context::get_instance()
89            .get_current_task_identifier()
90            .into_inner() as usize;
91
92        unsafe {
93            self.mutex.lock_mut(|state| {
94                // Check if current task owns the mutex
95                if let Some(owner) = state.task
96                    && owner == current_task
97                {
98                    if self.recursive && state.lock_count > 1 {
99                        // Decrement lock count for recursive mutex
100                        state.lock_count -= 1;
101                    } else {
102                        // Unlock the mutex
103                        state.task = None;
104                        state.lock_count = 0;
105                    }
106                    return true; // Successfully unlocked
107                }
108                false // Not owned by current task or not locked
109            })
110        }
111    }
112}
113
114#[unsafe(no_mangle)]
115pub static RAW_MUTEX_SIZE: usize = size_of::<RawMutex>();
116
117/// This function is used to initialize a mutex.
118///
119/// # Safety
120///
121/// This function is unsafe because it dereferences raw pointers.
122///
123/// # Errors
124///
125/// This function may return an error if the mutex is not initialized.
126#[unsafe(no_mangle)]
127pub unsafe extern "C" fn xila_initialize_mutex(mutex: *mut RawMutex) -> bool {
128    unsafe {
129        if mutex.is_null() {
130            return false;
131        }
132
133        if !(mutex as usize).is_multiple_of(align_of::<RawMutex>()) {
134            return false;
135        }
136
137        mutex.write(RawMutex::new(false));
138
139        true
140    }
141}
142
143/// Initialize a recursive mutex.
144///
145/// # Safety
146///
147/// The caller must ensure:
148/// - `mutex` points to valid, uninitialized memory
149/// - The memory is properly aligned for `Raw_mutex_type`
150/// - The memory will remain valid for the lifetime of the mutex
151#[unsafe(no_mangle)]
152pub unsafe extern "C" fn xila_initialize_recursive_mutex(mutex: *mut RawMutex) -> bool {
153    unsafe {
154        if mutex.is_null() {
155            return false;
156        }
157
158        if !(mutex as usize).is_multiple_of(align_of::<RawMutex>()) {
159            return false;
160        }
161
162        mutex.write(RawMutex::new(true));
163
164        true
165    }
166}
167
168/// Lock a mutex (blocking).
169///
170/// # Safety
171///
172/// The caller must ensure:
173/// - `mutex` points to a valid, initialized `Raw_mutex_type`
174/// - The mutex remains valid for the duration of the call
175#[unsafe(no_mangle)]
176pub unsafe extern "C" fn xila_lock_mutex(mutex: *mut RawMutex) -> bool {
177    unsafe {
178        let mutex = match RawMutex::from_mutable_pointer(mutex) {
179            Some(mutex) => mutex,
180            None => return false,
181        };
182
183        mutex.lock()
184    }
185}
186
187/// Unlock a mutex (blocking).
188///
189/// # Safety
190///
191/// The caller must ensure:
192/// - `mutex` points to a valid, initialized `Raw_mutex_type`
193/// - The mutex remains valid for the duration of the call
194/// - The current task owns the mutex
195#[unsafe(no_mangle)]
196pub unsafe extern "C" fn xila_unlock_mutex(mutex: *mut RawMutex) -> bool {
197    unsafe {
198        let mutex = match RawMutex::from_mutable_pointer(mutex) {
199            Some(mutex) => mutex,
200            None => return false,
201        };
202
203        mutex.unlock()
204    }
205}
206
207/// Destroy a mutex.
208///
209/// # Safety
210///
211/// The caller must ensure:
212/// - `mutex` points to a valid, initialized `Raw_mutex_type` allocated with Box
213/// - The mutex is not currently locked
214/// - No other threads are waiting on the mutex
215#[unsafe(no_mangle)]
216pub unsafe extern "C" fn xila_destroy_mutex(mutex: *mut RawMutex) -> bool {
217    unsafe {
218        let mutex = match RawMutex::from_mutable_pointer(mutex) {
219            Some(mutex) => mutex,
220            None => return false,
221        };
222
223        // Drop the mutex, which will release any resources it holds
224        drop_in_place(mutex);
225
226        true // Mutex is dropped here
227    }
228}