osal_rs/freertos/
semaphore.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//! Counting semaphore synchronization primitives for FreeRTOS.
21//!
22//! This module provides counting semaphores for resource management and signaling
23//! between threads and ISRs. Semaphores maintain a count and can be used to
24//! coordinate access to shared resources or signal event completion.
25
26use core::fmt::{Debug, Display};
27use core::ops::Deref;
28use core::ptr::null_mut;
29
30use super::ffi::{SemaphoreHandle, pdFAIL, pdFALSE};
31use super::system::System;
32use super::types::{BaseType, UBaseType};
33use crate::traits::{SemaphoreFn, SystemFn, ToTick};
34use crate::utils::{Error, Result, OsalRsBool};
35use crate::{vSemaphoreDelete, xSemaphoreCreateCounting, xSemaphoreGive, xSemaphoreGiveFromISR, xSemaphoreTake, xSemaphoreTakeFromISR};
36
37/// A counting semaphore for resource management and signaling.
38///
39/// Semaphores maintain a count that can be incremented (signaled) and decremented (waited).
40/// They are useful for:
41/// - Resource counting (e.g., managing a pool of N resources)
42/// - Event signaling between threads or from ISRs
43/// - Producer-consumer synchronization
44///
45/// # Examples
46///
47/// ## Basic binary semaphore (mutex alternative)
48///
49/// ```ignore
50/// use osal_rs::os::{Semaphore, SemaphoreFn};
51/// use core::time::Duration;
52/// 
53/// // Create a binary semaphore (max_count = 1)
54/// let sem = Semaphore::new(1, 1).unwrap();
55/// 
56/// // Wait (take) the semaphore
57/// if sem.wait(Duration::from_millis(100)).into() {
58///     // Critical section
59///     println!("Acquired semaphore");
60///     
61///     // Signal (give) the semaphore
62///     sem.signal();
63/// }
64/// ```
65///
66/// ## Resource pool management
67///
68/// ```ignore
69/// use osal_rs::os::{Semaphore, SemaphoreFn, Thread};
70/// use alloc::sync::Arc;
71/// use core::time::Duration;
72/// 
73/// // Create semaphore for 5 resources
74/// let resources = Arc::new(Semaphore::new(5, 5).unwrap());
75/// 
76/// let sem_clone = resources.clone();
77/// let worker = Thread::new("worker", 2048, 5, move || {
78///     loop {
79///         // Wait for an available resource
80///         if sem_clone.wait(Duration::from_secs(1)).into() {
81///             println!("Resource acquired");
82///             
83///             // Use resource...
84///             Duration::from_millis(500).sleep();
85///             
86///             // Release resource
87///             sem_clone.signal();
88///         }
89///     }
90/// }).unwrap();
91/// ```
92///
93/// ## Event signaling from ISR
94///
95/// ```ignore
96/// use osal_rs::os::{Semaphore, SemaphoreFn};
97/// use alloc::sync::Arc;
98/// 
99/// let event_sem = Arc::new(Semaphore::new(1, 0).unwrap());  // Initially unavailable
100/// let sem_clone = event_sem.clone();
101/// 
102/// // In interrupt handler:
103/// // sem_clone.signal_from_isr();  // Signal event occurred
104/// 
105/// // In thread:
106/// if event_sem.wait(1000).into() {
107///     println!("Event received!");
108/// }
109/// ```
110///
111/// ## Counting events
112///
113/// ```ignore
114/// use osal_rs::os::{Semaphore, SemaphoreFn};
115/// use core::time::Duration;
116/// 
117/// // Create semaphore with max_count=10, initially empty
118/// let counter = Semaphore::new(10, 0).unwrap();
119/// 
120/// // Signal 3 times
121/// counter.signal();
122/// counter.signal();
123/// counter.signal();
124/// 
125/// // Process 3 events
126/// for _ in 0..3 {
127///     if counter.wait(Duration::from_millis(10)).into() {
128///         println!("Processing event");
129///     }
130/// }
131/// ```
132pub struct Semaphore (SemaphoreHandle);
133
134unsafe impl Send for Semaphore {}
135unsafe impl Sync for Semaphore {}
136
137impl Semaphore {
138        /// Creates a new counting semaphore.
139    ///
140    /// # Parameters
141    ///
142    /// * `max_count` - Maximum count value the semaphore can reach
143    /// * `initial_count` - Initial count value
144    ///
145    /// # Returns
146    ///
147    /// * `Ok(Semaphore)` - Semaphore created successfully
148    /// * `Err(Error::OutOfMemory)` - Failed to allocate semaphore
149    ///
150    /// # Examples
151    ///
152    /// ```ignore
153    /// use osal_rs::os::{Semaphore, SemaphoreFn};
154    /// 
155    /// // Binary semaphore
156    /// let binary_sem = Semaphore::new(1, 1).unwrap();
157    /// 
158    /// // Counting semaphore for 5 resources
159    /// let counting_sem = Semaphore::new(5, 5).unwrap();
160    /// ```
161    pub fn new(max_count: UBaseType, initial_count: UBaseType) -> Result<Self> {
162        let handle = xSemaphoreCreateCounting!(max_count, initial_count);
163        if handle.is_null() {
164            Err(Error::OutOfMemory)
165        } else {
166            Ok(Self (handle))
167        }
168    }
169
170    /// Creates a counting semaphore with maximum possible count.
171    ///
172    /// Sets `max_count` to `UBaseType::MAX`.
173    ///
174    /// # Parameters
175    ///
176    /// * `initial_count` - Initial count value
177    ///
178    /// # Returns
179    ///
180    /// * `Ok(Semaphore)` - Semaphore created successfully
181    /// * `Err(Error::OutOfMemory)` - Failed to allocate
182    ///
183    /// # Examples
184    ///
185    /// ```ignore
186    /// use osal_rs::os::{Semaphore, SemaphoreFn};
187    /// 
188    /// let sem = Semaphore::new_with_count(0).unwrap();
189    /// ```
190    pub fn new_with_count(initial_count: UBaseType) -> Result<Self> {
191        let handle = xSemaphoreCreateCounting!(UBaseType::MAX, initial_count);
192        if handle.is_null() {
193            Err(Error::OutOfMemory)
194        } else {
195            Ok(Self (handle))
196        }
197    }
198
199}
200
201impl SemaphoreFn for Semaphore {
202
203    /// Waits to acquire the semaphore (decrements count).
204    ///
205    /// Blocks until semaphore is available or timeout expires.
206    ///
207    /// # Parameters
208    ///
209    /// * `ticks_to_wait` - Maximum time to wait (supports `Duration` via `ToTick`)
210    ///
211    /// # Returns
212    ///
213    /// * `OsalRsBool::True` - Semaphore acquired
214    /// * `OsalRsBool::False` - Timeout or error
215    ///
216    /// # Examples
217    ///
218    /// ```ignore
219    /// use osal_rs::os::{Semaphore, SemaphoreFn};
220    /// use core::time::Duration;
221    /// 
222    /// let sem = Semaphore::new(1, 1).unwrap();
223    /// if sem.wait(Duration::from_millis(100)).into() {
224    ///     // Critical section
225    ///     sem.signal();
226    /// }
227    /// ```
228    fn wait(&self, ticks_to_wait: impl ToTick) -> OsalRsBool {
229        if xSemaphoreTake!(self.0, ticks_to_wait.to_ticks()) != pdFAIL {
230            OsalRsBool::True
231        } else {
232            OsalRsBool::False
233        }
234    }
235
236    /// Waits to acquire the semaphore from ISR context (non-blocking).
237    ///
238    /// # Returns
239    ///
240    /// * `OsalRsBool::True` - Semaphore acquired
241    /// * `OsalRsBool::False` - Semaphore not available
242    ///
243    /// # Examples
244    ///
245    /// ```ignore
246    /// // In ISR:
247    /// if sem.wait_from_isr().into() {
248    ///     // Handle event
249    /// }
250    /// ```
251    fn wait_from_isr(&self) -> OsalRsBool {
252        let mut higher_priority_task_woken: BaseType = pdFALSE;
253        if xSemaphoreTakeFromISR!(self.0, &mut higher_priority_task_woken) != pdFAIL {
254
255            System::yield_from_isr(higher_priority_task_woken);
256
257            OsalRsBool::True
258        } else {
259
260            OsalRsBool::False
261        }
262    }
263    
264    /// Signals (releases) the semaphore (increments count).
265    ///
266    /// # Returns
267    ///
268    /// * `OsalRsBool::True` - Semaphore signaled successfully
269    /// * `OsalRsBool::False` - Error (e.g., count already at maximum)
270    ///
271    /// # Examples
272    ///
273    /// ```ignore
274    /// use osal_rs::os::{Semaphore, SemaphoreFn};
275    /// 
276    /// let sem = Semaphore::new(1, 0).unwrap();
277    /// sem.signal();  // Make semaphore available
278    /// ```
279    fn signal(&self) -> OsalRsBool {
280        if xSemaphoreGive!(self.0) != pdFAIL {
281            OsalRsBool::True
282        } else {
283            OsalRsBool::False
284        }
285    }
286    
287    /// Signals the semaphore from ISR context.
288    ///
289    /// Automatically yields to higher priority tasks if needed.
290    ///
291    /// # Returns
292    ///
293    /// * `OsalRsBool::True` - Semaphore signaled successfully
294    /// * `OsalRsBool::False` - Error
295    ///
296    /// # Examples
297    ///
298    /// ```ignore
299    /// // In ISR:
300    /// sem.signal_from_isr();
301    /// ```
302    fn signal_from_isr(&self) -> OsalRsBool {
303        let mut higher_priority_task_woken: BaseType = pdFALSE;
304        if xSemaphoreGiveFromISR!(self.0, &mut higher_priority_task_woken) != pdFAIL {
305            
306            System::yield_from_isr(higher_priority_task_woken);
307
308            OsalRsBool::True
309        } else {
310            OsalRsBool::False
311        }
312    }
313    
314    /// Deletes the semaphore and frees its resources.
315    ///
316    /// # Safety
317    ///
318    /// After calling this, the semaphore handle becomes invalid.
319    ///
320    /// # Examples
321    ///
322    /// ```ignore
323    /// let mut sem = Semaphore::new(1, 1).unwrap();
324    /// sem.delete();
325    /// ```
326    fn delete(&mut self) {
327        vSemaphoreDelete!(self.0);
328        self.0 = null_mut();
329    }
330
331
332}
333
334
335impl Drop for Semaphore {
336    fn drop(&mut self) {
337        if self.0.is_null() {
338            return;
339        }
340        self.delete();
341    }
342}
343
344impl Deref for Semaphore {
345    type Target = SemaphoreHandle;
346
347    fn deref(&self) -> &Self::Target {
348        &self.0
349    }
350}
351
352impl Debug for Semaphore {
353    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
354        f.debug_struct("Semaphore")
355            .field("handle", &self.0)
356            .finish()
357    }
358}
359
360impl Display for Semaphore {
361    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
362        write!(f, "Semaphore {{ handle: {:?} }}", self.0)
363    }
364}