freertos_next/
mutex.rs

1use crate::base::*;
2use crate::base_type::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
192#[cfg(feature = "recursive-mutex")]
193impl MutexInnerImpl for MutexRecursive {
194    fn create() -> Result<Self, FreeRtosError> {
195        let m = unsafe { freertos_rs_create_recursive_mutex() };
196        if m == 0 as *const _ {
197            return Err(FreeRtosError::OutOfMemory);
198        }
199        Ok(MutexRecursive(m))
200    }
201
202    fn take<D: DurationTicks>(&self, max_wait: D) -> Result<(), FreeRtosError> {
203        let res = unsafe { freertos_rs_take_recursive_semaphore(self.0, max_wait.to_ticks()) };
204
205        if res != 0 {
206            return Err(FreeRtosError::MutexTimeout);
207        }
208
209        Ok(())
210    }
211
212    fn give(&self) {
213        unsafe {
214            freertos_rs_give_recursive_semaphore(self.0);
215        }
216    }
217
218    #[inline]
219    unsafe fn from_raw_handle(handle: FreeRtosSemaphoreHandle) -> Self {
220        Self(handle)
221    }
222
223    #[inline]
224    fn raw_handle(&self) -> FreeRtosSemaphoreHandle {
225        self.0
226    }
227}
228
229#[cfg(feature = "recursive-mutex")]
230impl Drop for MutexRecursive {
231    fn drop(&mut self) {
232        unsafe { freertos_rs_delete_semaphore(self.0) }
233    }
234}
235
236impl fmt::Debug for MutexRecursive {
237    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
238        write!(f, "{:?}", self.0)
239    }
240}
241
242use mutex_traits::{ConstInit, RawMutex};
243/// `mutex-traits` implementation
244pub struct FreeRtosRawMutex {
245    inner: UnsafeCell<FreeRtosSemaphoreHandle>,
246}
247
248impl FreeRtosRawMutex {
249    /// Create a new `FreeRtosRawMutex`.
250    pub const fn empty() -> Self {
251        Self {
252            inner: UnsafeCell::new(core::ptr::null()),
253        }
254    }
255
256    fn get_inner(&self) -> &FreeRtosSemaphoreHandle {
257        let inner = unsafe { &mut *self.inner.get() };
258        if (*inner).is_null() {
259            critical_section::with(|_| {
260                if (*inner).is_null() {
261                    let m = unsafe { freertos_rs_create_mutex() };
262                    if m.is_null() {
263                        panic!();
264                    }
265                    *inner = m;
266                }
267            });
268        }
269        inner
270    }
271
272    #[inline]
273    fn try_lock_block(&self, block: bool) -> bool {
274        let t = if block {
275            FreeRtosTimeUnitsShimmed::get_max_wait()
276        } else {
277            0
278        };
279        let res = unsafe { freertos_rs_take_semaphore(*self.get_inner(), t) };
280        res == 0
281    }
282}
283
284unsafe impl Send for FreeRtosRawMutex {}
285
286impl ConstInit for FreeRtosRawMutex {
287    const INIT: Self = Self::empty();
288}
289
290unsafe impl RawMutex for FreeRtosRawMutex {
291    type GuardMarker = *mut ();
292
293    #[inline]
294    fn lock(&self) {
295        if !self.try_lock() {
296            panic!("Deadlocked");
297        }
298    }
299
300    #[inline]
301    fn try_lock(&self) -> bool {
302        self.try_lock_block(true)
303    }
304
305    #[inline]
306    unsafe fn unlock(&self) {
307        unsafe {
308            freertos_rs_give_semaphore(*self.get_inner());
309        }
310    }
311
312    #[inline]
313    fn is_locked(&self) -> bool {
314        if self.try_lock_block(false) {
315            unsafe {
316                self.unlock();
317            }
318            false
319        } else {
320            true
321        }
322    }
323}
324
325impl Drop for FreeRtosRawMutex {
326    fn drop(&mut self) {
327        unsafe { freertos_rs_delete_semaphore(*self.get_inner()) }
328    }
329}