freertos_rust/
semaphore.rs

1use crate::base::*;
2use crate::isr::*;
3use crate::shim::*;
4use crate::units::*;
5
6/// A counting or binary semaphore
7pub struct Semaphore {
8    semaphore: FreeRtosSemaphoreHandle,
9}
10
11unsafe impl Send for Semaphore {}
12unsafe impl Sync for Semaphore {}
13
14impl Semaphore {
15    /// Create a new binary semaphore
16    pub fn new_binary() -> Result<Semaphore, FreeRtosError> {
17        unsafe {
18            let s = freertos_rs_create_binary_semaphore();
19            if s == 0 as *const _ {
20                return Err(FreeRtosError::OutOfMemory);
21            }
22            Ok(Semaphore { semaphore: s })
23        }
24    }
25
26    /// Create a new counting semaphore
27    pub fn new_counting(max: u32, initial: u32) -> Result<Semaphore, FreeRtosError> {
28        unsafe {
29            let s = freertos_rs_create_counting_semaphore(max, initial);
30            if s == 0 as *const _ {
31                return Err(FreeRtosError::OutOfMemory);
32            }
33            Ok(Semaphore { semaphore: s })
34        }
35    }
36
37    /// # Safety
38    ///
39    /// `handle` must be a valid FreeRTOS semaphore handle.
40    ///
41    /// Only binary or counting semaphore is expected here.
42    /// To create mutex from raw handle use [`crate::mutex::MutexInnerImpl::from_raw_handle`].
43    #[inline]
44    pub unsafe fn from_raw_handle(handle: FreeRtosSemaphoreHandle) -> Self {
45        Self { semaphore: handle }
46    }
47    #[inline]
48    pub fn raw_handle(&self) -> FreeRtosSemaphoreHandle {
49        self.semaphore
50    }
51
52    /// Lock this semaphore in a RAII fashion
53    pub fn lock<D: DurationTicks>(&self, max_wait: D) -> Result<SemaphoreGuard<'_>, FreeRtosError> {
54        self.take(max_wait).map(|()| SemaphoreGuard { owner: self })
55    }
56
57    /// Returns `true` on success, `false` when semaphore count already reached its limit
58    pub fn give(&self) -> bool {
59        unsafe { freertos_rs_give_semaphore(self.semaphore) == 0 }
60    }
61
62    pub fn take<D: DurationTicks>(&self, max_wait: D) -> Result<(), FreeRtosError> {
63        unsafe {
64            let res = freertos_rs_take_semaphore(self.semaphore, max_wait.to_ticks());
65
66            if res != 0 {
67                return Err(FreeRtosError::Timeout);
68            }
69
70            Ok(())
71        }
72    }
73
74    /// Returns `true` on success, `false` when semaphore count already reached its limit
75    pub fn give_from_isr(&self, context: &mut InterruptContext) -> bool {
76        unsafe { freertos_rs_give_semaphore_isr(self.semaphore, context.get_task_field_mut()) == 0 }
77    }
78
79    /// Returns `true` on success, `false` if the semaphore was not successfully taken because it was not available
80    pub fn take_from_isr(&self, context: &mut InterruptContext) -> bool {
81        unsafe { freertos_rs_take_semaphore_isr(self.semaphore, context.get_task_field_mut()) == 0 }
82    }
83}
84
85impl Drop for Semaphore {
86    fn drop(&mut self) {
87        unsafe {
88            freertos_rs_delete_semaphore(self.semaphore);
89        }
90    }
91}
92
93/// Holds the lock to the semaphore until we are dropped
94pub struct SemaphoreGuard<'a> {
95    owner: &'a Semaphore,
96}
97
98impl<'a> Drop for SemaphoreGuard<'a> {
99    fn drop(&mut self) {
100        self.owner.give();
101    }
102}