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