veecle_osal_embassy/
thread.rs

1//! Thread-related abstractions.
2
3use core::num::NonZeroU64;
4pub use veecle_osal_api::thread::ThreadAbstraction;
5
6/// Implements the [`ThreadAbstraction`] trait for Embassy.
7///
8/// Only supports running on a single core (and thread) on `no_std` systems.
9/// Using the abstraction on any `no_std` system that uses multiple cores or threads may lead to undefined behavior.
10#[derive(Debug)]
11pub struct Thread;
12
13impl ThreadAbstraction for Thread {
14    #[cfg(not(target_os = "none"))]
15    fn current_thread_id() -> NonZeroU64 {
16        use std::cell::LazyCell;
17        use std::sync::atomic::{AtomicU64, Ordering};
18
19        /// Global counter for generating unique thread ids.
20        static NEXT_THREAD_ID: AtomicU64 = AtomicU64::new(1);
21
22        std::thread_local! {
23            /// Thread-local storage for the current thread's id.
24            static THREAD_ID: LazyCell<u64> = const { LazyCell::new(||{
25                // `Relaxed` is enough, we don't care about what specific value a thread sees.
26                // We just ensure that every value is unique.
27                // This assumes that creating 2^64 threads is impractical and no overflow occurs.
28                NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed)
29            }) };
30        }
31
32        NonZeroU64::new(THREAD_ID.with(|thread_id| **thread_id)).expect("overflow should not occur")
33    }
34
35    #[cfg(target_os = "none")]
36    fn current_thread_id() -> NonZeroU64 {
37        NonZeroU64::new(1).unwrap()
38    }
39}
40
41// Tests the `std` target only.
42#[cfg_attr(coverage_nightly, coverage(off))]
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn test_thread_id_consistency() {
49        let id1 = Thread::current_thread_id();
50        let id2 = Thread::current_thread_id();
51        assert_eq!(
52            id1, id2,
53            "Thread id should be consistent within the same thread"
54        );
55    }
56
57    #[test]
58    fn test_thread_id_uniqueness() {
59        let main_id = Thread::current_thread_id();
60
61        let handle1 = std::thread::spawn(Thread::current_thread_id);
62        let handle2 = std::thread::spawn(Thread::current_thread_id);
63
64        let thread1_id = handle1.join().unwrap();
65        let thread2_id = handle2.join().unwrap();
66
67        assert_ne!(
68            main_id, thread1_id,
69            "Main thread and thread 1 should have different ids"
70        );
71        assert_ne!(
72            main_id, thread2_id,
73            "Main thread and thread 2 should have different ids"
74        );
75        assert_ne!(
76            thread1_id, thread2_id,
77            "Thread 1 and thread 2 should have different ids"
78        );
79    }
80}