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
20//! Mutex synchronization primitives for FreeRTOS.
21//!
22//! This module provides safe mutual exclusion primitives built on top of FreeRTOS
23//! recursive mutexes. It supports RAII-style lock guards for automatic lock management
24//! and ISR-safe variants for interrupt contexts.
25
26use core::cell::UnsafeCell;
27use core::fmt::{Debug, Display, Formatter};
28use core::ops::{Deref, DerefMut};
29use core::marker::PhantomData;
30
31use alloc::sync::Arc;
32
33use super::ffi::{MutexHandle, pdFALSE, pdTRUE};
34use super::system::System;
35use crate::os::StaticMutexFn;
36use crate::traits::SystemFn;
37use crate::traits::{MutexGuardFn, RawMutexFn, MutexFn, ToTick};
38use crate::utils::{Result, Error, OsalRsBool, MAX_DELAY};
39use crate::{vSemaphoreDelete, xSemaphoreCreateRecursiveMutex, xSemaphoreGiveFromISR, xSemaphoreGiveRecursive, xSemaphoreTake, xSemaphoreTakeFromISR, xSemaphoreTakeRecursive};
40
41//// RawMutex ////
42
43/// Low-level recursive mutex wrapper for FreeRTOS.
44///
45/// This is the underlying implementation of the mutex that directly interfaces
46/// with FreeRTOS semaphore APIs. It's recursive, meaning the same thread can
47/// lock it multiple times.
48///
49/// # Note
50///
51/// Users should typically use [`Mutex<T>`] instead, which provides type-safe
52/// data protection. This type is exposed for advanced use cases.
53struct RawMutex(MutexHandle);
54
55unsafe impl Send for RawMutex {}
56unsafe impl Sync for RawMutex {}
57
58impl RawMutexFn for RawMutex {
59    fn new() -> Result<Self> {
60        let handle = xSemaphoreCreateRecursiveMutex!();
61        if handle.is_null() {
62            Err(Error::OutOfMemory)
63        } else {
64            Ok(RawMutex(handle))
65        }
66    }
67    
68    fn lock(&self) -> OsalRsBool {
69        let res = xSemaphoreTakeRecursive!(self.0, MAX_DELAY.to_ticks());
70        if res == pdTRUE {
71            OsalRsBool::True
72        } else {
73            OsalRsBool::False
74        }
75    }
76
77    fn lock_from_isr(&self) -> OsalRsBool {
78        let mut higher_priority_task_woken = pdFALSE;
79        let res = xSemaphoreTakeFromISR!(self.0, &mut higher_priority_task_woken);
80        if res == pdTRUE {
81
82            System::yield_from_isr(higher_priority_task_woken);
83
84            OsalRsBool::True
85        } else {
86            OsalRsBool::False
87        }
88    }
89
90    fn unlock(&self) -> OsalRsBool {
91        let res = xSemaphoreGiveRecursive!(self.0);
92        if res == pdTRUE {
93            OsalRsBool::True
94        } else {
95            OsalRsBool::False
96        }
97    }
98
99
100    fn unlock_from_isr(&self) -> OsalRsBool {
101        let mut higher_priority_task_woken = pdFALSE;
102        let res = xSemaphoreGiveFromISR!(self.0, &mut higher_priority_task_woken);
103        if res == pdTRUE {
104            
105            System::yield_from_isr(higher_priority_task_woken);
106            
107            OsalRsBool::True
108        } else {
109            OsalRsBool::False
110        }
111    }
112
113    fn delete(&mut self) {
114        vSemaphoreDelete!(self.0);
115        self.0 = core::ptr::null();
116    }
117}
118
119impl Drop for RawMutex {
120    fn drop(&mut self) {
121        if self.0.is_null() {
122            return;
123        }
124        self.delete();
125    }
126}
127
128impl Deref for RawMutex {
129    type Target = MutexHandle;
130
131    fn deref(&self) -> &MutexHandle {
132        &self.0
133    }
134}
135
136
137impl Debug for RawMutex {
138    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
139        f.debug_struct("RawMutex")
140            .field("handle", &self.0)
141            .finish()
142    }
143}
144
145impl Display for RawMutex {
146    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
147        write!(f, "RawMutex {{ handle: {:?} }}", self.0)
148    }
149}
150
151//// Mutex ////
152
153/// A mutual exclusion primitive useful for protecting shared data.
154///
155/// This mutex will block threads waiting for the lock to become available.
156/// The mutex is implemented using FreeRTOS recursive mutexes, supporting
157/// priority inheritance to prevent priority inversion.
158///
159/// # Type Parameters
160///
161/// * `T` - The type of data protected by the mutex
162///
163/// # Examples
164///
165/// ## Basic usage
166///
167/// ```ignore
168/// use osal_rs::os::Mutex;
169/// 
170/// let mutex = Mutex::new(0);
171/// 
172/// // Acquire the lock and modify the data
173/// {
174///     let mut guard = mutex.lock().unwrap();
175///     *guard += 1;
176/// }  // Lock is automatically released here
177/// ```
178///
179/// ## Sharing between threads
180///
181/// ```ignore
182/// use osal_rs::os::{Mutex, Thread};
183/// use alloc::sync::Arc;
184/// 
185/// let counter = Arc::new(Mutex::new(0));
186/// let counter_clone = counter.clone();
187/// 
188/// let thread = Thread::new("worker", 2048, 5, move || {
189///     let mut guard = counter_clone.lock().unwrap();
190///     *guard += 1;
191/// }).unwrap();
192/// 
193/// thread.start().unwrap();
194/// ```
195///
196/// ## Using from ISR context
197///
198/// ```ignore
199/// use osal_rs::os::Mutex;
200/// 
201/// let mutex = Mutex::new(0);
202/// 
203/// // In an interrupt handler:
204/// if let Ok(mut guard) = mutex.lock_from_isr() {
205///     *guard = 42;
206/// }
207/// ```
208pub struct Mutex<T: ?Sized> {
209    inner: RawMutex,
210    data: UnsafeCell<T>
211}
212
213
214unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
215unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
216
217impl<T: ?Sized> MutexFn<T> for Mutex<T> {
218    type Guard<'a> = MutexGuard<'a, T> where Self: 'a, T: 'a;
219    type GuardFromIsr<'a> = MutexGuardFromIsr<'a, T> where Self: 'a, T: 'a;
220
221    fn new(data: T) -> Self
222    where 
223        T: Sized
224    {
225        Self {
226            inner: RawMutex::new().unwrap(),
227            data: UnsafeCell::new(data),
228        }
229    }
230
231    fn lock(&self) -> Result<Self::Guard<'_>> {
232        match self.inner.lock() {
233            OsalRsBool::True => Ok(MutexGuard {
234                mutex: self,
235                _phantom: PhantomData,
236            }),
237            OsalRsBool::False => Err(Error::MutexLockFailed),
238        }
239    }
240
241    fn lock_from_isr(&self) -> Result<Self::GuardFromIsr<'_>> {
242        match self.inner.lock_from_isr() {
243            OsalRsBool::True => Ok(MutexGuardFromIsr {
244                mutex: self,
245                _phantom: PhantomData,
246            }),
247            OsalRsBool::False => Err(Error::MutexLockFailed),
248        }
249    }
250
251    /// Consumes the mutex and returns the inner data.
252    ///
253    /// This is safe because we have unique ownership of the mutex.
254    ///
255    /// # Examples
256    ///
257    /// ```ignore
258    /// use osal_rs::os::{Mutex, MutexFn};
259    /// 
260    /// let mutex = Mutex::new(5);
261    /// let value = mutex.into_inner().unwrap();
262    /// assert_eq!(value, 5);
263    /// ```
264    fn into_inner(self) -> Result<T> 
265    where 
266        Self: Sized, 
267        T: Sized 
268    {
269        Ok(self.data.into_inner())
270    }
271
272    /// Returns a mutable reference to the inner data.
273    ///
274    /// Since this takes `&mut self`, we know there are no other references
275    /// to the data, so we can safely return a mutable reference.
276    ///
277    /// # Examples
278    ///
279    /// ```ignore
280    /// use osal_rs::os::{Mutex, MutexFn};
281    /// 
282    /// let mut mutex = Mutex::new(0);
283    /// *mutex.get_mut() = 10;
284    /// assert_eq!(*mutex.get_mut(), 10);
285    /// ```
286    fn get_mut(&mut self) -> &mut T {
287        self.data.get_mut()
288    }
289}
290
291impl<T: ?Sized> Mutex<T> {
292    /// Acquires the mutex from ISR context, returning a specific ISR guard.
293    ///
294    /// This is an explicit version of `lock_from_isr` that returns the ISR-specific guard type.
295    ///
296    /// # Returns
297    ///
298    /// * `Ok(MutexGuardFromIsr)` - Lock acquired
299    /// * `Err(Error::MutexLockFailed)` - Failed to acquire lock
300    ///
301    /// # Examples
302    ///
303    /// ```ignore
304    /// // In ISR context:
305    /// if let Ok(guard) = mutex.lock_from_isr_explicit() {
306    ///     *guard = new_value;
307    /// }
308    /// ```
309    pub fn lock_from_isr_explicit(&self) -> Result<MutexGuardFromIsr<'_, T>> {
310        match self.inner.lock_from_isr() {
311            OsalRsBool::True => Ok(MutexGuardFromIsr {
312                mutex: self,
313                _phantom: PhantomData,
314            }),
315            OsalRsBool::False => Err(Error::MutexLockFailed),
316        }
317    }
318}
319
320impl<T> Mutex<T> {
321    /// Creates a new mutex wrapped in an Arc for easy sharing between threads.
322    ///
323    /// This is a convenience method equivalent to `Arc::new(Mutex::new(data))`.
324    ///
325    /// # Examples
326    ///
327    /// ```ignore
328    /// use osal_rs::os::Mutex;
329    /// use alloc::sync::Arc;
330    /// 
331    /// let shared_data = Mutex::new_arc(0u32);
332    /// let data_clone = Arc::clone(&shared_data);
333    /// 
334    /// // Use in thread...
335    /// let thread = Thread::new("worker", 2048, 5, move || {
336    ///     let mut guard = data_clone.lock().unwrap();
337    ///     *guard += 1;
338    /// });
339    /// ```
340    pub fn new_arc(data: T) -> Arc<Self> {
341        Arc::new(Self::new(data))
342    }
343}
344
345impl<T> Debug for Mutex<T> 
346where 
347    T: ?Sized {
348    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
349        f.debug_struct("Mutex")
350            .field("inner", &self.inner)
351            .finish()
352    }
353}
354
355impl<T> Display for Mutex<T> 
356where 
357    T: ?Sized {
358    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
359        write!(f, "Mutex {{ inner: {} }}", self.inner)
360    }   
361}
362
363//// MutexGuard ////
364
365/// RAII guard returned by `Mutex::lock()`.
366///
367/// When this guard goes out of scope, the mutex is automatically unlocked.
368/// Provides access to the protected data through `Deref` and `DerefMut`.
369///
370/// # Examples
371///
372/// ```ignore
373/// use osal_rs::os::{Mutex, MutexFn};
374/// 
375/// let mutex = Mutex::new(0);
376/// 
377/// {
378///     let mut guard = mutex.lock().unwrap();
379///     *guard += 1;  // Access protected data
380/// }  // Mutex automatically unlocked here
381/// ```
382pub struct MutexGuard<'a, T: ?Sized + 'a> {
383    mutex: &'a Mutex<T>,
384    _phantom: PhantomData<&'a mut T>,
385}
386
387impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
388    type Target = T;
389
390    fn deref(&self) -> &T {
391        unsafe { &*self.mutex.data.get() }
392    }
393}
394
395impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
396    fn deref_mut(&mut self) -> &mut T {
397        unsafe { &mut *self.mutex.data.get() }
398    }
399}
400
401impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
402    fn drop(&mut self) {
403        self.mutex.inner.unlock();
404    }
405}
406
407impl<'a, T: ?Sized> MutexGuardFn<'a, T> for MutexGuard<'a, T> {
408    /// Updates the protected value with a new value.
409    ///
410    /// # Note
411    ///
412    /// This requires `T` to implement `Clone` to copy the value.
413    /// Use the dereference operator directly for types that implement `Copy`.
414    ///
415    /// # Examples
416    ///
417    /// ```ignore
418    /// let mut guard = mutex.lock().unwrap();
419    /// let new_value = 42;
420    /// guard.update(&new_value);
421    /// ```
422    fn update(&mut self, t: &T) 
423    where
424        T: Clone
425    {
426        // Dereference twice: first to get &mut T from MutexGuard,
427        // then assign the cloned value
428        **self = t.clone();
429    }
430}
431
432/// RAII guard returned by `Mutex::lock_from_isr()`.
433///
434/// Similar to `MutexGuard` but specifically for ISR context.
435/// Automatically unlocks the mutex when dropped using ISR-safe unlock.
436///
437/// # Examples
438///
439/// ```ignore
440/// // In ISR context:
441/// if let Ok(mut guard) = mutex.lock_from_isr() {
442///     *guard = new_value;
443/// }  // Automatically unlocked with ISR-safe method
444/// ```
445pub struct MutexGuardFromIsr<'a, T: ?Sized + 'a> {
446    mutex: &'a Mutex<T>,
447    _phantom: PhantomData<&'a mut T>,
448}
449
450impl<'a, T: ?Sized> Deref for MutexGuardFromIsr<'a, T> {
451    type Target = T;
452
453    fn deref(&self) -> &T {
454        unsafe { &*self.mutex.data.get() }
455    }
456}
457
458impl<'a, T: ?Sized> DerefMut for MutexGuardFromIsr<'a, T> {
459    fn deref_mut(&mut self) -> &mut T {
460        unsafe { &mut *self.mutex.data.get() }
461    }
462}
463
464impl<'a, T: ?Sized> Drop for MutexGuardFromIsr<'a, T> {
465    fn drop(&mut self) {
466        self.mutex.inner.unlock_from_isr();
467    }
468}
469
470impl<'a, T: ?Sized> MutexGuardFn<'a, T> for MutexGuardFromIsr<'a, T> {
471    /// Updates the protected value from ISR context.
472    ///
473    /// # Note
474    ///
475    /// This requires `T` to implement `Clone` to copy the value.
476    ///
477    /// # Examples
478    ///
479    /// ```ignore
480    /// // In ISR context:
481    /// if let Ok(mut guard) = mutex.lock_from_isr() {
482    ///     guard.update(&new_value);
483    /// }
484    /// ```
485    fn update(&mut self, t: &T) 
486    where
487        T: Clone
488    {
489        **self = t.clone();
490    }
491}
492
493//// StaticMutex ////
494
495/// A statically-allocated mutex for protecting shared data.
496///
497/// Similar to `Mutex<T>` but designed to be allocated at compile time
498/// as a static variable. Requires explicit initialization before use.
499///
500/// # Examples
501///
502/// ```ignore
503/// use osal_rs::os::StaticMutex;
504/// 
505/// static mut COUNTER_MUTEX: Option<StaticMutex<u32>> = None;
506/// 
507/// // During initialization:
508/// unsafe {
509///     COUNTER_MUTEX = Some(StaticMutex::new(0).unwrap());
510/// }
511/// ```
512pub struct StaticMutex<T: ?Sized> {
513    inner: RawMutex,
514    data: UnsafeCell<T>,
515}
516
517impl<T> StaticMutex<T> {
518    /// Creates a new static mutex protecting the given data.
519    ///
520    /// # Parameters
521    ///
522    /// * `data` - The initial value to protect
523    ///
524    /// # Returns
525    ///
526    /// * `Ok(StaticMutex)` - Successfully created
527    /// * `Err(Error::OutOfMemory)` - Failed to allocate mutex resources
528    ///
529    /// # Examples
530    ///
531    /// ```ignore
532    /// let mutex = StaticMutex::new(42).unwrap();
533    /// ```
534    pub fn new(data: T) -> Result<Self>  {
535        Ok(Self {
536            inner: RawMutex::new()?, 
537            data: UnsafeCell::new(data),
538        })
539    }
540}
541
542
543impl<T> StaticMutexFn<T> for StaticMutex<T> {
544    type Guard<'a> = StaticMutexGuard<'a, T> where Self: 'a, T: 'a;
545    type GuardFromIsr<'a> = StaticMutexGuardFromIsr<'a, T> where Self: 'a, T: 'a;
546
547    /// Acquires the lock and returns a guard.
548    ///
549    /// Blocks until the lock is available.
550    fn lock(&self) -> Result<StaticMutexGuard<'_, T>> {
551        match self.inner.lock() {
552            OsalRsBool::True => Ok(StaticMutexGuard {
553                mutex: self,
554                _phantom: core::marker::PhantomData,
555            }),
556            OsalRsBool::False => Err(Error::MutexLockFailed),
557        }
558    }
559
560    /// Acquires the lock from ISR context and returns an ISR guard.
561    ///
562    /// Non-blocking version for interrupt service routines.
563    fn lock_from_isr(&self) -> Result<StaticMutexGuardFromIsr<'_, T>> {
564        match self.inner.lock_from_isr() {
565            OsalRsBool::True => Ok(StaticMutexGuardFromIsr {
566                mutex: self,
567                _phantom: core::marker::PhantomData,
568            }),
569            OsalRsBool::False => Err(Error::MutexLockFailed),
570        }
571    }
572
573    /// Returns a mutable reference to the underlying data.
574    ///
575    /// Safe because it requires exclusive mutable access to the mutex.
576    fn get_mut(&mut self) -> &mut T {
577        unsafe { &mut *self.data.get() }
578    }
579}
580
581impl<T> StaticMutex<T> {
582    /// Initializes the mutex.
583    ///
584    /// Note: The mutex is already initialized in the constructor.
585    /// This method is provided for API compatibility.
586    ///
587    /// # Returns
588    ///
589    /// Always returns `Ok(())`
590    pub fn init(&mut self) -> Result<()> {
591        // Mutex is already initialized in the constructor
592        // This method exists for API compatibility
593        Ok(())
594    }
595}
596
597/// RAII guard for `StaticMutex` returned by `lock()`.
598///
599/// Automatically releases the mutex when dropped. Provides access to
600/// the protected data through `Deref` and `DerefMut`.
601pub struct StaticMutexGuard<'a, T: ?Sized + 'a> {
602    mutex: &'a StaticMutex<T>,
603    _phantom: core::marker::PhantomData<&'a mut T>,
604}
605
606impl<'a, T: ?Sized> Deref for StaticMutexGuard<'a, T> {
607    type Target = T;
608
609    fn deref(&self) -> &T {
610        unsafe { &*self.mutex.data.get() }
611    }
612}
613
614impl<'a, T: ?Sized> DerefMut for StaticMutexGuard<'a, T> {
615    fn deref_mut(&mut self) -> &mut T {
616        unsafe { &mut *self.mutex.data.get() }
617    }
618}
619
620impl<'a, T: ?Sized> Drop for StaticMutexGuard<'a, T> {
621    fn drop(&mut self) {
622        self.mutex.inner.unlock();
623    }
624}
625
626/// RAII guard for `StaticMutex` returned by `lock_from_isr()`.
627///
628/// Similar to `StaticMutexGuard` but for ISR context. Automatically
629/// releases the mutex using ISR-safe unlock when dropped.
630pub struct StaticMutexGuardFromIsr<'a, T: ?Sized + 'a> {
631    mutex: &'a StaticMutex<T>,
632    _phantom: core::marker::PhantomData<&'a mut T>,
633}
634
635impl<'a, T: ?Sized> Deref for StaticMutexGuardFromIsr<'a, T> {
636    type Target = T;
637
638    fn deref(&self) -> &T {
639        unsafe { &*self.mutex.data.get() }
640    }
641}
642
643impl<'a, T: ?Sized> DerefMut for StaticMutexGuardFromIsr<'a, T> {
644    fn deref_mut(&mut self) -> &mut T {
645        unsafe { &mut *self.mutex.data.get() }
646    }
647}
648
649impl<'a, T: ?Sized> Drop for StaticMutexGuardFromIsr<'a, T> {
650    fn drop(&mut self) {
651        self.mutex.inner.unlock_from_isr();
652    }
653}