freertos_next/
mutex.rs

1use crate::base::*;
2use crate::prelude::v1::*;
3use crate::shim::*;
4use crate::units::*;
5
6pub type Mutex<T> = MutexImpl<T, MutexNormal>;
7pub type RecursiveMutex<T> = MutexImpl<T, MutexRecursive>;
8
9unsafe impl<T: Send, M> Send for MutexImpl<T, M> {}
10
11unsafe impl<T: Send, M> Sync for MutexImpl<T, M> {}
12
13/// Mutual exclusion access to a contained value. Can be recursive -
14/// the current owner of a lock can re-lock it.
15pub struct MutexImpl<T: ?Sized, M> {
16    mutex: M,
17    data: UnsafeCell<T>,
18}
19
20impl<T: ?Sized, M> fmt::Debug for MutexImpl<T, M>
21where
22    M: MutexInnerImpl + fmt::Debug,
23{
24    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25        write!(f, "Mutex address: {:?}", self.mutex)
26    }
27}
28
29impl<T, M> MutexImpl<T, M>
30where
31    M: MutexInnerImpl,
32{
33    /// Create a new mutex with the given inner value
34    pub fn new(value: T) -> Result<Self, FreeRtosError> {
35        Ok(Self::from_parts(M::create()?, value))
36    }
37
38    /// Try to obtain a lock and mutable access to our inner value
39    pub fn lock<D: DurationTicks>(
40        &self,
41        max_wait: D,
42    ) -> Result<MutexGuard<'_, T, M>, FreeRtosError> {
43        self.mutex.take(max_wait)?;
44
45        Ok(MutexGuard {
46            __mutex: &self.mutex,
47            __data: &self.data,
48        })
49    }
50
51    /// Consume the mutex and return its inner value
52    pub fn into_inner(self) -> T {
53        self.into_parts().1
54    }
55
56    /// Get mutable reference to inner value.
57    ///
58    /// This method does not lock the mutex because mutable reference guarantees exclusive access.
59    pub fn get_mut(&mut self) -> &mut T {
60        self.data.get_mut()
61    }
62
63    /// Create owning mutex from non-owning mutex and inner value.
64    ///
65    /// It is safe to pass an already locked `mutex` although it is not recommended.
66    pub fn from_parts(mutex: M, value: T) -> Self {
67        Self {
68            mutex,
69            data: UnsafeCell::new(value),
70        }
71    }
72
73    /// Split owning mutex into non-owning mutex and inner value.
74    pub fn into_parts(self) -> (M, T) {
75        (self.mutex, self.data.into_inner())
76    }
77
78    /// Get mutable reference to inner non-owning mutex.
79    pub fn inner_mutex_mut(&mut self) -> &mut M {
80        &mut self.mutex
81    }
82}
83
84/// Holds the mutex until we are dropped
85pub struct MutexGuard<'a, T: ?Sized + 'a, M: 'a>
86where
87    M: MutexInnerImpl,
88{
89    __mutex: &'a M,
90    __data: &'a UnsafeCell<T>,
91}
92
93impl<'mutex, T: ?Sized, M> Deref for MutexGuard<'mutex, T, M>
94where
95    M: MutexInnerImpl,
96{
97    type Target = T;
98
99    fn deref<'a>(&'a self) -> &'a T {
100        unsafe { &*self.__data.get() }
101    }
102}
103
104impl<'mutex, T: ?Sized, M> DerefMut for MutexGuard<'mutex, T, M>
105where
106    M: MutexInnerImpl,
107{
108    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
109        unsafe { &mut *self.__data.get() }
110    }
111}
112
113impl<'a, T: ?Sized, M> Drop for MutexGuard<'a, T, M>
114where
115    M: MutexInnerImpl,
116{
117    fn drop(&mut self) {
118        self.__mutex.give();
119    }
120}
121
122pub trait MutexInnerImpl
123where
124    Self: Sized,
125{
126    fn create() -> Result<Self, FreeRtosError>;
127    fn take<D: DurationTicks>(&self, max_wait: D) -> Result<(), FreeRtosError>;
128    fn give(&self);
129
130    /// # Safety
131    ///
132    /// `handle` must be a valid FreeRTOS mutex handle.
133    ///
134    /// The type of `handle` (normal or recursive mutex) must match the type
135    /// of instance being created ([`MutexNormal`] or [`MutexRecursive`] respectively).
136    unsafe fn from_raw_handle(handle: FreeRtosSemaphoreHandle) -> Self;
137    fn raw_handle(&self) -> FreeRtosSemaphoreHandle;
138}
139
140pub struct MutexNormal(FreeRtosSemaphoreHandle);
141
142impl MutexInnerImpl for MutexNormal {
143    fn create() -> Result<Self, FreeRtosError> {
144        let m = unsafe { freertos_rs_create_mutex() };
145        if m == 0 as *const _ {
146            return Err(FreeRtosError::OutOfMemory);
147        }
148        Ok(MutexNormal(m))
149    }
150
151    fn take<D: DurationTicks>(&self, max_wait: D) -> Result<(), FreeRtosError> {
152        let res = unsafe { freertos_rs_take_semaphore(self.0, max_wait.to_ticks()) };
153
154        if res != 0 {
155            return Err(FreeRtosError::MutexTimeout);
156        }
157
158        Ok(())
159    }
160
161    fn give(&self) {
162        unsafe {
163            freertos_rs_give_semaphore(self.0);
164        }
165    }
166
167    #[inline]
168    unsafe fn from_raw_handle(handle: FreeRtosSemaphoreHandle) -> Self {
169        Self(handle)
170    }
171
172    #[inline]
173    fn raw_handle(&self) -> FreeRtosSemaphoreHandle {
174        self.0
175    }
176}
177
178impl Drop for MutexNormal {
179    fn drop(&mut self) {
180        unsafe { freertos_rs_delete_semaphore(self.0) }
181    }
182}
183
184impl fmt::Debug for MutexNormal {
185    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186        write!(f, "{:?}", self.0)
187    }
188}
189
190pub struct MutexRecursive(FreeRtosSemaphoreHandle);
191
192impl MutexInnerImpl for MutexRecursive {
193    fn create() -> Result<Self, FreeRtosError> {
194        let m = unsafe { freertos_rs_create_recursive_mutex() };
195        if m == 0 as *const _ {
196            return Err(FreeRtosError::OutOfMemory);
197        }
198        Ok(MutexRecursive(m))
199    }
200
201    fn take<D: DurationTicks>(&self, max_wait: D) -> Result<(), FreeRtosError> {
202        let res = unsafe { freertos_rs_take_recursive_semaphore(self.0, max_wait.to_ticks()) };
203
204        if res != 0 {
205            return Err(FreeRtosError::MutexTimeout);
206        }
207
208        Ok(())
209    }
210
211    fn give(&self) {
212        unsafe {
213            freertos_rs_give_recursive_semaphore(self.0);
214        }
215    }
216
217    #[inline]
218    unsafe fn from_raw_handle(handle: FreeRtosSemaphoreHandle) -> Self {
219        Self(handle)
220    }
221
222    #[inline]
223    fn raw_handle(&self) -> FreeRtosSemaphoreHandle {
224        self.0
225    }
226}
227
228impl Drop for MutexRecursive {
229    fn drop(&mut self) {
230        unsafe { freertos_rs_delete_semaphore(self.0) }
231    }
232}
233
234impl fmt::Debug for MutexRecursive {
235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236        write!(f, "{:?}", self.0)
237    }
238}
239
240use mutex_traits::{ConstInit, RawMutex};
241/// `mutex-traits` implementation
242pub struct FreeRtosRawMutex {
243    inner: UnsafeCell<FreeRtosSemaphoreHandle>,
244}
245
246impl FreeRtosRawMutex {
247    /// Create a new `FreeRtosRawMutex`.
248    pub const fn empty() -> Self {
249        Self {
250            inner: UnsafeCell::new(core::ptr::null()),
251        }
252    }
253
254    fn get_inner(&self) -> &FreeRtosSemaphoreHandle {
255        let inner = unsafe { &mut *self.inner.get() };
256        if (*inner).is_null() {
257            critical_section::with(|_| {
258                if (*inner).is_null() {
259                    let m = unsafe { freertos_rs_create_mutex() };
260                    if m.is_null() {
261                        panic!();
262                    }
263                    *inner = m;
264                }
265            });
266        }
267        inner
268    }
269
270    #[inline]
271    fn try_lock_block(&self, block: bool) -> bool {
272        let t = if block {
273            FreeRtosTimeUnitsShimmed::get_max_wait()
274        } else {
275            0
276        };
277        let res = unsafe { freertos_rs_take_semaphore(*self.get_inner(), t) };
278        res == 0
279    }
280}
281
282unsafe impl Send for FreeRtosRawMutex {}
283
284impl ConstInit for FreeRtosRawMutex {
285    const INIT: Self = Self::empty();
286}
287
288unsafe impl RawMutex for FreeRtosRawMutex {
289    type GuardMarker = *mut ();
290
291    #[inline]
292    fn lock(&self) {
293        if !self.try_lock() {
294            panic!("Deadlocked");
295        }
296    }
297
298    #[inline]
299    fn try_lock(&self) -> bool {
300        self.try_lock_block(true)
301    }
302
303    #[inline]
304    unsafe fn unlock(&self) {
305        unsafe {
306            freertos_rs_give_semaphore(*self.get_inner());
307        }
308    }
309
310    #[inline]
311    fn is_locked(&self) -> bool {
312        if self.try_lock_block(false) {
313            unsafe {
314                self.unlock();
315            }
316            false
317        } else {
318            true
319        }
320    }
321}
322
323impl Drop for FreeRtosRawMutex {
324    fn drop(&mut self) {
325        unsafe { freertos_rs_delete_semaphore(*self.get_inner()) }
326    }
327}