Skip to main content

osal_rs/traits/
thread.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 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//! Thread-related traits and type definitions.
21//!
22//! This module provides the core abstractions for creating and managing RTOS tasks/threads,
23//! including thread lifecycle, notifications, and priority management.
24//!
25//! # Overview
26//!
27//! In RTOS terminology, tasks and threads are often used interchangeably. This module
28//! uses "Thread" for consistency with Rust conventions, but these map directly to
29//! RTOS tasks.
30//!
31//! # Thread Lifecycle
32//!
33//! 1. **Creation**: Use `Thread::new()` with name, stack size, and priority
34//! 2. **Spawning**: Call `spawn()` or `spawn_simple()` with the thread function
35//! 3. **Execution**: Thread runs until function returns or `delete()` is called
36//! 4. **Cleanup**: Call `delete()` to free resources
37//!
38//! # Thread Notifications
39//!
40//! Threads support lightweight task notifications as an alternative to semaphores
41//! and queues for simple signaling. See `ThreadNotification` for available actions.
42//!
43//! # Priority Management
44//!
45//! Higher priority threads preempt lower priority ones. Priority 0 is typically
46//! reserved for the idle task. Use `ToPriority` trait for flexible priority specification.
47
48use core::any::Any;
49use alloc::boxed::Box;
50use alloc::sync::Arc;
51
52use crate::os::{ThreadMetadata};
53use crate::os::types::{BaseType, TickType, UBaseType};
54use crate::utils::{Result, DoublePtr};
55
56/// Type-erased parameter that can be passed to thread callbacks.
57///
58/// Allows passing arbitrary data to thread functions in a thread-safe manner.
59/// The parameter is wrapped in an `Arc` for safe sharing across thread boundaries
60/// and can be downcast to its original type using `downcast_ref()`.
61///
62/// # Thread Safety
63///
64/// The inner type must implement `Any + Send + Sync` to ensure it can be
65/// safely shared between threads.
66///
67/// # Examples
68///
69/// ```ignore
70/// use std::sync::Arc;
71/// use osal_rs::traits::ThreadParam;
72///
73/// // Create a parameter
74/// let param: ThreadParam = Arc::new(42u32);
75///
76/// // In the thread callback, downcast to access
77/// if let Some(value) = param.downcast_ref::<u32>() {
78///     println!("Received: {}", value);
79/// }
80/// ```
81pub type ThreadParam = Arc<dyn Any + Send + Sync>;
82
83/// Thread callback function pointer type.
84///
85/// Thread callbacks receive a boxed thread handle and optional parameter,
86/// and can return an updated parameter value.
87///
88/// # Parameters
89///
90/// - `Box<dyn Thread>` - Handle to the thread itself (for self-reference)
91/// - `Option<ThreadParam>` - Optional type-erased parameter passed at spawn time
92///
93/// # Returns
94///
95/// `Result<ThreadParam>` - Updated parameter or error
96///
97/// # Trait Bounds
98///
99/// The function must be `Send + Sync + 'static` to be safely used across
100/// thread boundaries and to live for the duration of the thread.
101///
102/// # Examples
103///
104/// ```ignore
105/// use osal_rs::os::{Thread, ThreadParam};
106/// use std::sync::Arc;
107///
108/// let callback: Box<ThreadFnPtr> = Box::new(|thread, param| {
109///     if let Some(p) = param {
110///         if let Some(count) = p.downcast_ref::<u32>() {
111///             println!("Count: {}", count);
112///         }
113///     }
114///     Ok(Arc::new(0u32))
115/// });
116/// ```
117pub type ThreadFnPtr = dyn Fn(Box<dyn Thread>, Option<ThreadParam>) -> Result<ThreadParam> + Send + Sync + 'static;
118
119/// Simple thread function pointer type without parameters.
120///
121/// Used for basic thread functions that don't need access to the thread handle
122/// or parameters. This is the simplest form of thread callback.
123///
124/// # Trait Bounds
125///
126/// The function must be `Send + Sync + 'static` to be safely used in a
127/// multi-threaded environment.
128///
129/// # Examples
130///
131/// ```ignore
132/// use osal_rs::os::Thread;
133///
134/// let mut thread = Thread::new("simple", 1024, 1);
135/// thread.spawn_simple(|| {
136///     loop {
137///         println!("Hello from thread!");
138///         System::delay(1000);
139///     }
140/// }).unwrap();
141/// ```
142pub type ThreadSimpleFnPtr = dyn Fn() + Send + Sync + 'static;
143
144/// Thread notification actions.
145///
146/// Defines different ways to notify a thread using the FreeRTOS task notification mechanism.
147/// Task notifications provide a lightweight alternative to semaphores and queues for
148/// simple signaling between threads or from ISRs to threads.
149///
150/// # Performance
151///
152/// Task notifications are faster and use less memory than semaphores or queues,
153/// but each thread has only one notification value (32 bits).
154///
155/// # Common Patterns
156///
157/// - **Event Signaling**: Use `Increment` or `SetBits` to signal events
158/// - **Value Passing**: Use `SetValueWithOverwrite` to pass a value
159/// - **Non-Blocking Updates**: Use `SetValueWithoutOverwrite` to avoid data races
160///
161/// # Examples
162///
163/// ```ignore
164/// use osal_rs::os::{Thread, ThreadNotification};
165/// 
166/// let thread = Thread::current();
167/// 
168/// // Increment notification counter
169/// thread.notify(ThreadNotification::Increment);
170/// 
171/// // Set specific bits (can combine multiple events)
172/// thread.notify(ThreadNotification::SetBits(0b1010));
173/// 
174/// // Set value, overwriting any existing value
175/// thread.notify(ThreadNotification::SetValueWithOverwrite(42));
176/// 
177/// // Set value only if no pending notifications
178/// thread.notify(ThreadNotification::SetValueWithoutOverwrite(100));
179/// ```
180#[derive(Debug, Copy, Clone)]
181pub enum ThreadNotification {
182    /// Don't update the notification value.
183    ///
184    /// Can be used to just query whether a task has been notified.
185    NoAction,
186    /// Bitwise OR the notification value with the specified bits.
187    ///
188    /// Useful for setting multiple event flags that accumulate.
189    SetBits(u32),
190    /// Increment the notification value by one.
191    ///
192    /// Useful for counting events or implementing a lightweight counting semaphore.
193    Increment,
194    /// Set the notification value, overwriting any existing value.
195    ///
196    /// Use when you want to send a value and don't care if it overwrites
197    /// a previous unread value.
198    SetValueWithOverwrite(u32),
199    /// Set the notification value only if the receiving thread has no pending notifications.
200    ///
201    /// Use when you want to avoid overwriting an unread value. Returns an error
202    /// if a notification is already pending.
203    SetValueWithoutOverwrite(u32),
204}
205
206impl Into<(u32, u32)> for ThreadNotification {
207    fn into(self) -> (u32, u32) {
208        use ThreadNotification::*;
209        match self {
210            NoAction => (0, 0),
211            SetBits(bits) => (1, bits),
212            Increment => (2, 0),
213            SetValueWithOverwrite(value) => (3, value),
214            SetValueWithoutOverwrite(value) => (4, value),
215        }
216    }
217}
218
219/// Core thread/task trait.
220///
221/// Provides methods for thread lifecycle management, synchronization,
222/// and communication through task notifications.
223///
224/// # Thread Creation
225///
226/// Threads are typically created with `Thread::new()` specifying name,
227/// stack size, and priority, then started with `spawn()` or `spawn_simple()`.
228///
229/// # Thread Safety
230///
231/// All methods are thread-safe. ISR-specific methods (suffixed with `_from_isr`)
232/// should only be called from interrupt context.
233///
234/// # Resource Management
235///
236/// Threads should be properly deleted with `delete()` when no longer needed
237/// to free stack memory and control structures.
238///
239/// # Examples
240///
241/// ```ignore
242/// use osal_rs::os::{Thread, System};
243/// use std::sync::Arc;
244///
245/// // Create and spawn a simple thread
246/// let mut thread = Thread::new("worker", 2048, 5);
247/// thread.spawn_simple(|| {
248///     loop {
249///         println!("Working...");
250///         System::delay(1000);
251///     }
252/// }).unwrap();
253///
254/// // Create thread with parameter
255/// let mut thread2 = Thread::new("counter", 1024, 5);
256/// let counter = Arc::new(0u32);
257/// thread2.spawn(Some(counter.clone()), |_thread, param| {
258///     // Use param here
259///     Ok(param.unwrap())
260/// }).unwrap();
261/// ```
262pub trait Thread {
263    /// Spawns a thread with a callback function and optional parameter.
264    ///
265    /// Creates and starts a new thread that executes the provided callback function.
266    /// The callback receives a handle to itself and an optional parameter.
267    ///
268    /// # Parameters
269    ///
270    /// * `param` - Optional type-erased parameter passed to the callback
271    /// * `callback` - Function to execute in the thread context
272    ///
273    /// # Returns
274    ///
275    /// * `Ok(Self)` - Thread spawned successfully
276    /// * `Err(Error)` - Failed to create or start thread
277    ///
278    /// # Examples
279    ///
280    /// ```ignore
281    /// use osal_rs::os::Thread;
282    /// use std::sync::Arc;
283    ///
284    /// let mut thread = Thread::new("worker", 1024, 5);
285    /// let counter = Arc::new(100u32);
286    ///
287    /// thread.spawn(Some(counter.clone()), |thread, param| {
288    ///     if let Some(p) = param {
289    ///         if let Some(count) = p.downcast_ref::<u32>() {
290    ///             println!("Starting with count: {}", count);
291    ///         }
292    ///     }
293    ///     Ok(Arc::new(200u32))
294    /// }).unwrap();
295    /// ```
296    fn spawn<F>(&mut self, param: Option<ThreadParam>, callback: F) -> Result<Self>
297    where 
298        F: Fn(Box<dyn Thread>, Option<ThreadParam>) -> Result<ThreadParam>,
299        F: Send + Sync + 'static,
300        Self: Sized;
301
302    /// Spawns a simple thread with a callback function (no parameters).
303    ///
304    /// Creates and starts a new thread that executes the provided callback.
305    /// This is a simpler version of `spawn()` for threads that don't need
306    /// parameters or self-reference.
307    ///
308    /// # Parameters
309    ///
310    /// * `callback` - Function to execute in the thread context
311    ///
312    /// # Returns
313    ///
314    /// * `Ok(Self)` - Thread spawned successfully
315    /// * `Err(Error)` - Failed to create or start thread
316    ///
317    /// # Examples
318    ///
319    /// ```ignore
320    /// use osal_rs::os::{Thread, System};
321    ///
322    /// let mut thread = Thread::new("blinker", 512, 3);
323    /// thread.spawn_simple(|| {
324    ///     loop {
325    ///         toggle_led();
326    ///         System::delay(500);
327    ///     }
328    /// }).unwrap();
329    /// ```
330    fn spawn_simple<F>(&mut self, callback: F) -> Result<Self>
331    where
332        F: Fn() + Send + Sync + 'static,
333        Self: Sized;
334
335    /// Deletes the thread and frees its resources.
336    ///
337    /// Terminates the thread and releases its stack and control structures.
338    /// After calling this, the thread handle becomes invalid.
339    ///
340    /// # Safety
341    ///
342    /// - The thread should not be holding any resources (mutexes, etc.)
343    /// - Other threads should not be waiting on this thread
344    /// - Cannot delete the currently running thread (use from another thread)
345    ///
346    /// # Examples
347    ///
348    /// ```ignore
349    /// use osal_rs::os::Thread;
350    ///
351    /// let mut thread = Thread::new("temp", 512, 1);
352    /// thread.spawn_simple(|| {
353    ///     // Do some work
354    /// }).unwrap();
355    ///
356    /// // Later, from another thread
357    /// thread.delete();
358    /// ```
359    fn delete(&self);
360
361    /// Suspends the thread.
362    ///
363    /// Prevents the thread from executing until `resume()` is called.
364    /// The thread state is preserved and can be resumed later.
365    ///
366    /// # Use Cases
367    ///
368    /// - Temporarily pause a thread
369    /// - Debugging and development
370    /// - Dynamic task management
371    ///
372    /// # Examples
373    ///
374    /// ```ignore
375    /// use osal_rs::os::Thread;
376    ///
377    /// let thread = Thread::current();
378    /// thread.suspend();  // Pauses this thread
379    /// ```
380    fn suspend(&self);
381
382    /// Resumes a suspended thread.
383    ///
384    /// Resumes execution of a thread that was previously suspended with `suspend()`.
385    /// If the thread was not suspended, this has no effect.
386    ///
387    /// # Examples
388    ///
389    /// ```ignore
390    /// // Thread 1
391    /// worker_thread.suspend();
392    ///
393    /// // Thread 2
394    /// worker_thread.resume();  // Resume Thread 1
395    /// ```
396    fn resume(&self);
397
398    /// Waits for the thread to complete and retrieves its return value.
399    ///
400    /// Blocks the calling thread until this thread terminates. The thread's
401    /// return value is stored in the provided pointer.
402    ///
403    /// # Parameters
404    ///
405    /// * `retval` - Pointer to store the thread's return value
406    ///
407    /// # Returns
408    ///
409    /// * `Ok(exit_code)` - Thread completed successfully
410    /// * `Err(Error)` - Join operation failed
411    ///
412    /// # Examples
413    ///
414    /// ```ignore
415    /// use osal_rs::os::Thread;
416    ///
417    /// let mut thread = Thread::new("worker", 1024, 1);
418    /// thread.spawn_simple(|| {
419    ///     // Do work
420    /// }).unwrap();
421    ///
422    /// let mut retval = core::ptr::null_mut();
423    /// thread.join(&mut retval).unwrap();
424    /// ```
425    fn join(&self, retval: DoublePtr) -> Result<i32>;
426
427    /// Gets metadata about the thread.
428    ///
429    /// Returns information such as thread name, priority, stack usage,
430    /// and current state.
431    ///
432    /// # Returns
433    ///
434    /// `ThreadMetadata` structure containing thread information
435    ///
436    /// # Examples
437    ///
438    /// ```ignore
439    /// use osal_rs::os::Thread;
440    ///
441    /// let thread = Thread::current();
442    /// let meta = thread.get_metadata();
443    /// println!("Thread: {} Priority: {}", meta.name, meta.priority);
444    /// ```
445    fn get_metadata(&self) -> ThreadMetadata;
446
447    /// Gets a handle to the currently executing thread.
448    ///
449    /// Returns a handle to the thread that is currently running.
450    /// Useful for self-referential operations.
451    ///
452    /// # Returns
453    ///
454    /// Handle to the current thread
455    ///
456    /// # Examples
457    ///
458    /// ```ignore
459    /// use osal_rs::os::Thread;
460    ///
461    /// let current = Thread::get_current();
462    /// let meta = current.get_metadata();
463    /// println!("Running in thread: {}", meta.name);
464    /// ```
465    fn get_current() -> Self
466    where 
467        Self: Sized;
468
469    /// Sends a notification to the thread.
470    ///
471    /// Notifies the thread using the specified notification action.
472    /// Task notifications are a lightweight signaling mechanism.
473    ///
474    /// # Parameters
475    ///
476    /// * `notification` - The notification action to perform
477    ///
478    /// # Returns
479    ///
480    /// * `Ok(())` - Notification sent successfully
481    /// * `Err(Error)` - Failed to send notification
482    ///
483    /// # Examples
484    ///
485    /// ```ignore
486    /// use osal_rs::os::{Thread, ThreadNotification};
487    ///
488    /// let worker = get_worker_thread();
489    /// 
490    /// // Signal an event
491    /// worker.notify(ThreadNotification::SetBits(0b0001)).unwrap();
492    /// 
493    /// // Send a value
494    /// worker.notify(ThreadNotification::SetValueWithOverwrite(42)).unwrap();
495    /// ```
496    fn notify(&self, notification: ThreadNotification) -> Result<()>;
497
498    /// Sends a notification to the thread from ISR context.
499    ///
500    /// ISR-safe version of `notify()`. Must only be called from interrupt context.
501    ///
502    /// # Parameters
503    ///
504    /// * `notification` - The notification action to perform
505    /// * `higher_priority_task_woken` - Set to non-zero if a context switch should occur
506    ///
507    /// # Returns
508    ///
509    /// * `Ok(())` - Notification sent successfully
510    /// * `Err(Error)` - Failed to send notification
511    ///
512    /// # Examples
513    ///
514    /// ```ignore
515    /// use osal_rs::os::{Thread, ThreadNotification, System};
516    ///
517    /// // In interrupt handler
518    /// fn isr_handler() {
519    ///     let worker = get_worker_thread();
520    ///     let mut task_woken = 0;
521    ///     
522    ///     worker.notify_from_isr(
523    ///         ThreadNotification::Increment,
524    ///         &mut task_woken
525    ///     ).ok();
526    ///     
527    ///     System::yield_from_isr(task_woken);
528    /// }
529    /// ```
530    fn notify_from_isr(&self, notification: ThreadNotification, higher_priority_task_woken: &mut BaseType) -> Result<()>;
531
532    /// Waits for a notification.
533    ///
534    /// Blocks the calling thread until a notification is received or timeout occurs.
535    /// Allows clearing specific bits on entry and/or exit.
536    ///
537    /// # Parameters
538    ///
539    /// * `bits_to_clear_on_entry` - Bits to clear before waiting
540    /// * `bits_to_clear_on_exit` - Bits to clear after receiving notification
541    /// * `timeout_ticks` - Maximum ticks to wait (0 = no wait, MAX = wait forever)
542    ///
543    /// # Returns
544    ///
545    /// * `Ok(notification_value)` - Notification received, returns the notification value
546    /// * `Err(Error::Timeout)` - No notification received within timeout
547    /// * `Err(Error)` - Other error occurred
548    ///
549    /// # Note
550    ///
551    /// This method does not use `ToTick` trait to maintain dynamic dispatch compatibility.
552    ///
553    /// # Examples
554    ///
555    /// ```ignore
556    /// use osal_rs::os::Thread;
557    ///
558    /// let current = Thread::get_current();
559    ///
560    /// // Wait for notification, clear all bits on exit
561    /// match current.wait_notification(0, 0xFFFFFFFF, 1000) {
562    ///     Ok(value) => println!("Notified with value: {}", value),
563    ///     Err(_) => println!("Timeout waiting for notification"),
564    /// }
565    ///
566    /// // Wait for specific bits
567    /// let bits_of_interest = 0b0011;
568    /// match current.wait_notification(0, bits_of_interest, 5000) {
569    ///     Ok(value) => {
570    ///         if value & bits_of_interest != 0 {
571    ///             println!("Received expected bits");
572    ///         }
573    ///     },
574    ///     Err(_) => println!("Timeout"),
575    /// }
576    /// ```
577    fn wait_notification(&self, bits_to_clear_on_entry: u32, bits_to_clear_on_exit: u32 , timeout_ticks: TickType) -> Result<u32>;
578
579
580}
581
582/// Trait for converting types to thread priority values.
583///
584/// Allows flexible specification of thread priorities using different types
585/// (e.g., integers, enums) that can be converted to the underlying RTOS
586/// priority representation.
587///
588/// # Priority Ranges
589///
590/// Priority 0 is typically reserved for the idle task. Higher numbers
591/// indicate higher priority (preemptive scheduling).
592///
593/// # Examples
594///
595/// ```ignore
596/// use osal_rs::traits::ToPriority;
597///
598/// // Implement for a custom priority enum
599/// enum TaskPriority {
600///     Low,
601///     Medium,
602///     High,
603/// }
604///
605/// impl ToPriority for TaskPriority {
606///     fn to_priority(&self) -> UBaseType {
607///         match self {
608///             TaskPriority::Low => 1,
609///             TaskPriority::Medium => 5,
610///             TaskPriority::High => 10,
611///         }
612///     }
613/// }
614///
615/// let thread = Thread::new("worker", 1024, TaskPriority::High);
616/// ```
617pub trait ToPriority {
618    /// Converts this value to a priority.
619    ///
620    /// # Returns
621    ///
622    /// The priority value as `UBaseType`
623    fn to_priority(&self) -> UBaseType;
624}