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