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