osal_rs/freertos/
mutex.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2023/2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 ***************************************************************************/
19
20use core::cell::UnsafeCell;
21use core::fmt::{Debug, Display, Formatter};
22use core::ops::{Deref, DerefMut};
23use core::marker::PhantomData;
24
25use alloc::sync::Arc;
26
27use super::ffi::{MutexHandle, pdFALSE, pdTRUE};
28use super::system::System;
29use crate::traits::SystemFn;
30use crate::traits::{MutexGuardFn, RawMutexFn, MutexFn, ToTick};
31use crate::utils::{Result, Error, OsalRsBool, MAX_DELAY};
32use crate::{vSemaphoreDelete, xSemaphoreCreateRecursiveMutex, xSemaphoreGiveFromISR, xSemaphoreGiveRecursive, xSemaphoreTake, xSemaphoreTakeFromISR, xSemaphoreTakeRecursive};
33
34
35struct RawMutex(MutexHandle);
36
37unsafe impl Send for RawMutex {}
38unsafe impl Sync for RawMutex {}
39
40impl RawMutexFn for RawMutex {
41    fn new() -> Result<Self> {
42        let handle = xSemaphoreCreateRecursiveMutex!();
43        if handle.is_null() {
44            Err(Error::OutOfMemory)
45        } else {
46            Ok(RawMutex(handle))
47        }
48    }
49    
50    fn lock(&self) -> OsalRsBool {
51        let res = xSemaphoreTakeRecursive!(self.0, MAX_DELAY.to_ticks());
52        if res == pdTRUE {
53            OsalRsBool::True
54        } else {
55            OsalRsBool::False
56        }
57    }
58
59    fn lock_from_isr(&self) -> OsalRsBool {
60        let mut higher_priority_task_woken = pdFALSE;
61        let res = xSemaphoreTakeFromISR!(self.0, &mut higher_priority_task_woken);
62        if res == pdTRUE {
63
64            System::yield_from_isr(higher_priority_task_woken);
65
66            OsalRsBool::True
67        } else {
68            OsalRsBool::False
69        }
70    }
71
72    fn unlock(&self) -> OsalRsBool {
73        let res = xSemaphoreGiveRecursive!(self.0);
74        if res == pdTRUE {
75            OsalRsBool::True
76        } else {
77            OsalRsBool::False
78        }
79    }
80
81
82    fn unlock_from_isr(&self) -> OsalRsBool {
83        let mut higher_priority_task_woken = pdFALSE;
84        let res = xSemaphoreGiveFromISR!(self.0, &mut higher_priority_task_woken);
85        if res == pdTRUE {
86            
87            System::yield_from_isr(higher_priority_task_woken);
88            
89            OsalRsBool::True
90        } else {
91            OsalRsBool::False
92        }
93    }
94
95    fn delete(&mut self) {
96        vSemaphoreDelete!(self.0);
97        self.0 = core::ptr::null();
98    }
99}
100
101impl Drop for RawMutex {
102    fn drop(&mut self) {
103        if self.0.is_null() {
104            return;
105        }
106        self.delete();
107    }
108}
109
110impl Deref for RawMutex {
111    type Target = MutexHandle;
112
113    fn deref(&self) -> &MutexHandle {
114        &self.0
115    }
116}
117
118
119impl Debug for RawMutex {
120    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
121        f.debug_struct("RawMutex")
122            .field("handle", &self.0)
123            .finish()
124    }
125}
126
127impl Display for RawMutex {
128    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
129        write!(f, "RawMutex {{ handle: {:?} }}", self.0)
130    }
131}
132
133pub struct Mutex<T: ?Sized> {
134    inner: RawMutex,
135    data: UnsafeCell<T>
136}
137
138
139unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
140unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
141
142impl<T: ?Sized> MutexFn<T> for Mutex<T> {
143    type Guard<'a> = MutexGuard<'a, T> where Self: 'a, T: 'a;
144    type GuardFromIsr<'a> = MutexGuardFromIsr<'a, T> where Self: 'a, T: 'a;
145
146    fn new(data: T) -> Self
147    where 
148        T: Sized
149    {
150        Self {
151            inner: RawMutex::new().unwrap(),
152            data: UnsafeCell::new(data),
153        }
154    }
155
156    fn lock(&self) -> Result<Self::Guard<'_>> {
157        match self.inner.lock() {
158            OsalRsBool::True => Ok(MutexGuard {
159                mutex: self,
160                _phantom: PhantomData,
161            }),
162            OsalRsBool::False => Err(Error::MutexLockFailed),
163        }
164    }
165
166    fn lock_from_isr(&self) -> Result<Self::GuardFromIsr<'_>> {
167        match self.inner.lock_from_isr() {
168            OsalRsBool::True => Ok(MutexGuardFromIsr {
169                mutex: self,
170                _phantom: PhantomData,
171            }),
172            OsalRsBool::False => Err(Error::MutexLockFailed),
173        }
174    }
175
176    fn into_inner(self) -> Result<T> 
177    where 
178        Self: Sized, 
179        T: Sized 
180    {
181        Ok(self.data.into_inner())
182    }
183
184    fn get_mut(&mut self) -> &mut T {
185        self.data.get_mut()
186    }
187}
188
189impl<T: ?Sized> Mutex<T> {
190    /// Acquires the mutex from ISR context, returning a specific ISR guard
191    pub fn lock_from_isr_explicit(&self) -> Result<MutexGuardFromIsr<'_, T>> {
192        match self.inner.lock_from_isr() {
193            OsalRsBool::True => Ok(MutexGuardFromIsr {
194                mutex: self,
195                _phantom: PhantomData,
196            }),
197            OsalRsBool::False => Err(Error::MutexLockFailed),
198        }
199    }
200}
201
202impl<T> Mutex<T> {
203    /// Creates a new mutex wrapped in an Arc for easy sharing between threads.
204    /// This is a convenience method that combines `Arc::new(Mutex::new(data))`.
205    /// 
206    /// # Example
207    /// ```ignore
208    /// let shared_data = Mutex::new_arc(0u32);
209    /// let data_clone = Arc::clone(&shared_data);
210    /// ```
211    pub fn new_arc(data: T) -> Arc<Self> {
212        Arc::new(Self::new(data))
213    }
214}
215
216impl<T> Debug for Mutex<T> 
217where 
218    T: ?Sized {
219    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
220        f.debug_struct("Mutex")
221            .field("inner", &self.inner)
222            .finish()
223    }
224}
225
226impl<T> Display for Mutex<T> 
227where 
228    T: ?Sized {
229    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
230        write!(f, "Mutex {{ inner: {} }}", self.inner)
231    }   
232}
233
234/// RAII guard returned by `Mutex::lock`
235pub struct MutexGuard<'a, T: ?Sized + 'a> {
236    mutex: &'a Mutex<T>,
237    _phantom: PhantomData<&'a mut T>,
238}
239
240impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
241    type Target = T;
242
243    fn deref(&self) -> &T {
244        unsafe { &*self.mutex.data.get() }
245    }
246}
247
248impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
249    fn deref_mut(&mut self) -> &mut T {
250        unsafe { &mut *self.mutex.data.get() }
251    }
252}
253
254impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
255    fn drop(&mut self) {
256        self.mutex.inner.unlock();
257    }
258}
259
260impl<'a, T: ?Sized> MutexGuardFn<'a, T> for MutexGuard<'a, T> {}
261
262pub struct MutexGuardFromIsr<'a, T: ?Sized + 'a> {
263    mutex: &'a Mutex<T>,
264    _phantom: PhantomData<&'a mut T>,
265}
266
267impl<'a, T: ?Sized> Deref for MutexGuardFromIsr<'a, T> {
268    type Target = T;
269
270    fn deref(&self) -> &T {
271        unsafe { &*self.mutex.data.get() }
272    }
273}
274
275impl<'a, T: ?Sized> DerefMut for MutexGuardFromIsr<'a, T> {
276    fn deref_mut(&mut self) -> &mut T {
277        unsafe { &mut *self.mutex.data.get() }
278    }
279}
280
281impl<'a, T: ?Sized> Drop for MutexGuardFromIsr<'a, T> {
282    fn drop(&mut self) {
283        self.mutex.inner.unlock_from_isr();
284    }
285}
286
287impl<'a, T: ?Sized> MutexGuardFn<'a, T> for MutexGuardFromIsr<'a, T> {}