zephyr/sys/
thread.rs

1//! Zephyr low level threads
2//!
3//! This is a fairly low level (but still safe) interface to Zephyr threads.  This is intended to
4//! work the same way as threads are typically done on Zephyr systems, where the threads and their
5//! stacks are statically allocated, a code is called to initialize them.
6//!
7//! In addition, there are some convenience operations available that require allocation to be
8//! available.
9//!
10//! ## Usage
11//!
12//! Each thread needs a stack associated with it.  The stack and the thread should be defined as
13//! follows:
14//! ```
15//! kobj_defined! {
16//!     static MY_THREAD: StaticThread;
17//!     static MY_THREAD_STACK: StaticThreadStack<2048>;
18//! }
19//! ```
20//!
21//! Each of these has a [`init_once`] method that returns the single usable instance.  The
22//! StaticThread takes the stack retrieved by take as its argument.  This will return a
23//! ThreadStarter, where various options can be set on the thread, and then it started with one of
24//! `spawn`, or `simple_spawn` (spawn requires `CONFIG_RUST_ALLOC`).
25//!
26//! Provided that `CONFIG_RUST_ALLOC` has been enabled (recommended): the read can be initialized as
27//! follows:
28//! ```
29//! let mut thread = MY_THREAD.init_once(MY_THREAD_STACK.init_once(()).unwrap()).unwrap();
30//! thread.set_priority(5);
31//! let child = thread.spawn(|| move {
32//!     // thread code...
33//! });
34//! ```
35//!
36//! [`init_once`]: StaticKernelObject::init_once
37
38#[cfg(CONFIG_RUST_ALLOC)]
39extern crate alloc;
40
41#[cfg(CONFIG_RUST_ALLOC)]
42use alloc::boxed::Box;
43use core::{
44    cell::UnsafeCell,
45    ffi::{c_int, c_void, CStr},
46    mem,
47};
48
49use super::K_NO_WAIT;
50use zephyr_sys::{
51    k_thread, k_thread_create, k_thread_entry_t, k_thread_name_set, k_tid_t,
52    z_thread_stack_element, ZR_STACK_ALIGN, ZR_STACK_RESERVED,
53};
54
55use crate::{
56    align::AlignAs,
57    object::{StaticKernelObject, Wrapped},
58    sync::atomic::AtomicUsize,
59};
60
61/// Adjust the stack size for alignment.  Note that, unlike the C code, we don't include the
62/// reservation in this, as it has its own fields in the struct.
63pub const fn stack_len(size: usize) -> usize {
64    size.next_multiple_of(ZR_STACK_ALIGN)
65}
66
67#[doc(hidden)]
68/// A Zephyr stack declaration.
69///
70/// It isn't meant to be used directly, as it needs additional decoration about linker sections and
71/// such.  Unlike the C declaration, the reservation is a separate field.  As long as the SIZE is
72/// properly aligned, this should work without padding between the fields.
73pub struct RealStaticThreadStack<const SIZE: usize> {
74    #[allow(dead_code)]
75    align: AlignAs<ZR_STACK_ALIGN>,
76    #[allow(dead_code)]
77    pub data: UnsafeCell<[z_thread_stack_element; SIZE]>,
78    #[allow(dead_code)]
79    extra: [z_thread_stack_element; ZR_STACK_RESERVED],
80}
81
82unsafe impl<const SIZE: usize> Sync for RealStaticThreadStack<SIZE> {}
83
84/// The dynamic stack value, which wraps the underlying stack.
85pub struct ThreadStack {
86    base: *mut z_thread_stack_element,
87    size: usize,
88}
89
90impl ThreadStack {
91    /// Construct a new `ThreadStack` from a raw base pointer and size.
92    pub unsafe fn new(base: *mut z_thread_stack_element, size: usize) -> Self {
93        Self { base, size }
94    }
95
96    /// Returns the base pointer of the stack.
97    pub fn base(&self) -> *mut z_thread_stack_element {
98        self.base
99    }
100
101    /// Returns the size of the stack.
102    pub fn size(&self) -> usize {
103        self.size
104    }
105}
106
107#[doc(hidden)]
108pub struct StaticThreadStack {
109    pub base: *mut z_thread_stack_element,
110    pub size: usize,
111}
112
113unsafe impl Sync for StaticKernelObject<StaticThreadStack> {}
114
115/*
116// Let's make sure I can declare some of this.
117pub static TEST_STACK: RealStaticThreadStack<1024> = unsafe { ::core::mem::zeroed() };
118pub static TEST: StaticKernelObject<StaticThreadStack> = StaticKernelObject {
119    value: UnsafeCell::new(StaticThreadStack {
120        base: TEST_STACK.data.get() as *mut z_thread_stack_element,
121        size: 1024,
122    }),
123    init: AtomicUsize::new(0),
124};
125
126pub fn doit() {
127    TEST.init_once(());
128}
129*/
130
131impl Wrapped for StaticKernelObject<StaticThreadStack> {
132    type T = ThreadStack;
133    type I = ();
134    fn get_wrapped(&self, _args: Self::I) -> Self::T {
135        // This is a bit messy.  Whee.
136        let stack = self.value.get();
137        let stack = unsafe { &*stack };
138        unsafe { ThreadStack::new(stack.base, stack.size) }
139    }
140}
141
142impl StaticKernelObject<StaticThreadStack> {
143    /// Construct a StaticThreadStack object.
144    ///
145    /// This is not intended to be directly called, but is used by the [`kobj_define`] macro.
146    #[doc(hidden)]
147    pub const fn new_from<const SZ: usize>(real: &RealStaticThreadStack<SZ>) -> Self {
148        Self {
149            value: UnsafeCell::new(StaticThreadStack {
150                base: real.data.get() as *mut z_thread_stack_element,
151                size: SZ,
152            }),
153            init: AtomicUsize::new(0),
154        }
155    }
156
157    /// Construct an array of StaticThreadStack kernel objects, based on the same sized array of the
158    /// RealStaticThreadStack objects.
159    ///
160    /// This is not intended to be directly called, but is used by the [`kobj_define`] macro.
161    #[doc(hidden)]
162    pub const fn new_from_array<const SZ: usize, const N: usize>(
163        real: &[RealStaticThreadStack<SZ>; N],
164    ) -> [Self; N] {
165        // Rustc currently doesn't support iterators in constant functions, but it does allow simple
166        // looping.  Since the value is not Copy, we need to use the MaybeUninit with a bit of
167        // unsafe.  This initialization is safe, as we loop through all of the entries, giving them
168        // a value.
169        //
170        // In addition, MaybeUninit::uninit_array is not stable, so do this the old unsafe way.
171        // let mut res: [MaybeUninit<Self>; N] = MaybeUninit::uninit_array();
172        // Note that `mem::uninitialized` in addition to being deprecated, isn't const.  But, since
173        // this is a const computation, zero-filling shouldn't hurt anything.
174        let mut res: [Self; N] = unsafe { mem::zeroed() };
175        let mut i = 0;
176        while i < N {
177            res[i] = Self::new_from(&real[i]);
178            i += 1;
179        }
180        res
181    }
182}
183
184/// A single Zephyr thread.
185///
186/// This wraps a `k_thread` type within Rust.  This value is returned from
187/// [`StaticThread::init_once`] and represents an initialized thread that hasn't been started.
188pub struct Thread {
189    raw: *mut k_thread,
190    stack: ThreadStack,
191
192    /// The initial priority of this thread.
193    priority: c_int,
194    /// Options given to thread creation.
195    options: u32,
196    /// The name to be given to the thread, if desired.
197    name: Option<&'static CStr>,
198}
199
200/// A statically defined thread.
201pub type StaticThread = StaticKernelObject<k_thread>;
202
203unsafe impl Sync for StaticThread {}
204
205impl Wrapped for StaticKernelObject<k_thread> {
206    type T = Thread;
207    type I = ThreadStack;
208    fn get_wrapped(&self, stack: Self::I) -> Self::T {
209        Thread {
210            raw: self.value.get(),
211            stack,
212            priority: 0,
213            options: 0,
214            name: None,
215        }
216    }
217}
218
219impl Thread {
220    /// Set the priority the thread will be created at.
221    pub fn set_priority(&mut self, priority: c_int) {
222        self.priority = priority;
223    }
224
225    /// Set the value of the options passed to thread creation.
226    pub fn set_options(&mut self, options: u32) {
227        self.options = options;
228    }
229
230    /// Set a name for this thread.
231    ///
232    /// Attempts to set the name of this thread, if Zephyr if configured to do so.  Has no effect
233    /// otherwise.
234    pub fn set_name(&mut self, name: &'static CStr) {
235        self.name = Some(name);
236    }
237
238    /// Simple thread spawn.  This is unsafe because of the raw values being used.  This can be
239    /// useful in systems without an allocator defined.
240    ///
241    /// # Safety
242    ///
243    /// Safe use follows similar requirements to using this safely from within C code.  Passing Rust
244    /// values through this interface is difficult to get right, and it is generally recommended to
245    /// use [`spawn`].
246    ///
247    /// [`spawn`]: Self::spawn
248    pub unsafe fn simple_spawn(
249        mut self,
250        child: k_thread_entry_t,
251        p1: *mut c_void,
252        p2: *mut c_void,
253        p3: *mut c_void,
254    ) {
255        let tid = k_thread_create(
256            self.raw,
257            self.stack.base(),
258            self.stack.size(),
259            child,
260            p1,
261            p2,
262            p3,
263            self.priority,
264            self.options,
265            K_NO_WAIT,
266        );
267
268        self.set_thread_name(tid);
269    }
270
271    #[cfg(CONFIG_RUST_ALLOC)]
272    /// Spawn a thread, with a closure.
273    ///
274    /// This requires allocation to be able to safely pass the closure to the other thread.
275    pub fn spawn<F: FnOnce() + Send + 'static>(mut self, child: F) {
276        use core::ptr::null_mut;
277
278        let child: closure::Closure = Box::new(child);
279        let child = Box::into_raw(Box::new(closure::ThreadData { closure: child }));
280        unsafe {
281            let tid = k_thread_create(
282                self.raw,
283                self.stack.base(),
284                self.stack.size(),
285                Some(closure::child),
286                child as *mut c_void,
287                null_mut(),
288                null_mut(),
289                self.priority,
290                self.options,
291                K_NO_WAIT,
292            );
293
294            self.set_thread_name(tid);
295        }
296    }
297
298    fn set_thread_name(&mut self, tid: k_tid_t) {
299        if let Some(name) = self.name {
300            unsafe {
301                k_thread_name_set(tid, name.as_ptr());
302            }
303        }
304    }
305}
306
307/*
308use zephyr_sys::{
309    k_thread, k_thread_create, k_thread_start, z_thread_stack_element, ZR_STACK_ALIGN, ZR_STACK_RESERVED
310};
311
312use core::{cell::UnsafeCell, ffi::c_void, ptr::null_mut};
313
314use crate::{align::AlignAs, object::{KobjInit, StaticKernelObject}};
315
316#[cfg(CONFIG_RUST_ALLOC)]
317extern crate alloc;
318#[cfg(CONFIG_RUST_ALLOC)]
319use alloc::boxed::Box;
320#[cfg(CONFIG_RUST_ALLOC)]
321use core::mem::ManuallyDrop;
322
323use super::K_FOREVER;
324
325/// Adjust the stack size for alignment.  Note that, unlike the C code, we don't include the
326/// reservation in this, as it has its own fields in the struct.
327pub const fn stack_len(size: usize) -> usize {
328    size.next_multiple_of(ZR_STACK_ALIGN)
329}
330
331/// A Zephyr stack declaration.  It isn't meant to be used directly, as it needs additional
332/// decoration about linker sections and such.  Unlike the C declaration, the reservation is a
333/// separate field.  As long as the SIZE is properly aligned, this should work without padding
334/// between the fields.
335pub struct ThreadStack<const SIZE: usize> {
336    #[allow(dead_code)]
337    align: AlignAs<ZR_STACK_ALIGN>,
338    data: UnsafeCell<[z_thread_stack_element; SIZE]>,
339    #[allow(dead_code)]
340    extra: [z_thread_stack_element; ZR_STACK_RESERVED],
341}
342
343unsafe impl<const SIZE: usize> Sync for ThreadStack<SIZE> {}
344
345impl<const SIZE: usize> ThreadStack<SIZE> {
346    /// Get the size of this stack.  This is the size, minus any reservation.  This is called `size`
347    /// to avoid any confusion with `len` which might return the actual size of the stack.
348    pub fn size(&self) -> usize {
349        SIZE
350    }
351
352    /// Return the stack base needed as the argument to various zephyr calls.
353    pub fn base(&self) -> *mut z_thread_stack_element {
354        self.data.get() as *mut z_thread_stack_element
355    }
356
357    /// Return the token information for this stack, which is a base and size.
358    pub fn token(&self) -> StackToken {
359        StackToken { base: self.base(), size: self.size() }
360    }
361}
362
363/// Declare a variable, of a given name, representing the stack for a thread.
364#[macro_export]
365macro_rules! kernel_stack_define {
366    ($name:ident, $size:expr) => {
367        #[link_section = concat!(".noinit.", stringify!($name), ".", file!(), line!())]
368        static $name: $crate::sys::thread::ThreadStack<{$crate::sys::thread::stack_len($size)}>
369            = unsafe { ::core::mem::zeroed() };
370    };
371}
372
373/// A single Zephyr thread.
374///
375/// This wraps a `k_thread` type within Zephyr.  This value is returned
376/// from the `StaticThread::spawn` method, to allow control over the start
377/// of the thread.  The [`start`] method should be used to start the
378/// thread.
379///
380/// [`start`]: Thread::start
381pub struct Thread {
382    raw: *mut k_thread,
383}
384
385unsafe impl Sync for StaticKernelObject<k_thread> { }
386
387impl KobjInit<k_thread, Thread> for StaticKernelObject<k_thread> {
388    fn wrap(ptr: *mut k_thread) -> Thread {
389        Thread { raw: ptr }
390    }
391}
392
393// Public interface to threads.
394impl Thread {
395    /// Start execution of the given thread.
396    pub fn start(&self) {
397        unsafe { k_thread_start(self.raw) }
398    }
399}
400
401/// Declare a global static representing a thread variable.
402#[macro_export]
403macro_rules! kernel_thread_define {
404    ($name:ident) => {
405        // Since the static object has an atomic that we assume is initialized, let the compiler put
406        // this in the data section it finds appropriate (probably .bss if it is initialized to zero).
407        // This only matters when the objects are being checked.
408        // TODO: This doesn't seem to work with the config.
409        // #[cfg_attr(not(CONFIG_RUST_CHECK_KOBJ_INIT),
410        //            link_section = concat!(".noinit.", stringify!($name), ".", file!(), line!()))]
411        static $name: $crate::object::StaticKernelObject<$crate::raw::k_thread> =
412            $crate::object::StaticKernelObject::new();
413        // static $name: $crate::sys::thread::Thread = unsafe { ::core::mem::zeroed() };
414    };
415}
416
417/// For now, this "token" represents the somewhat internal information about thread.
418/// What we really want is to make sure that stacks and threads go together.
419pub struct StackToken {
420    base: *mut z_thread_stack_element,
421    size: usize,
422}
423
424// This isn't really safe at all, as these can be initialized.  It is unclear how, if even if it is
425// possible to implement safe static threads and other data structures in Zephyr.
426
427/// A Statically defined Zephyr `k_thread` object to be used from Rust.
428///
429/// This should be used in a manner similar to:
430/// ```
431/// const MY_STACK_SIZE: usize = 4096;
432///
433/// kobj_define! {
434///     static MY_THREAD: StaticThread;
435///     static MY_STACK: ThreadStack<MY_STACK_SIZE>;
436/// }
437///
438/// let thread = MY_THREAD.spawn(MY_STACK.token(), move || {
439///     // Body of thread.
440/// });
441/// thread.start();
442/// ```
443pub type StaticThread = StaticKernelObject<k_thread>;
444
445// The thread itself assumes we've already initialized, so this method is on the wrapper.
446impl StaticThread {
447    /// Spawn this thread to the given external function.  This is a simplified version that doesn't
448    /// take any arguments.  The child runs immediately.
449    pub fn simple_spawn(&self, stack: StackToken, child: fn() -> ()) -> Thread {
450        self.init_help(|raw| {
451            unsafe {
452                k_thread_create(
453                    raw,
454                    stack.base,
455                    stack.size,
456                    Some(simple_child),
457                    child as *mut c_void,
458                    null_mut(),
459                    null_mut(),
460                    5,
461                    0,
462                    K_FOREVER,
463                );
464            }
465        });
466        self.get()
467    }
468
469    #[cfg(CONFIG_RUST_ALLOC)]
470    /// Spawn a thread, running a closure.  The closure will be boxed to give to the new thread.
471    /// The new thread runs immediately.
472    pub fn spawn<F: FnOnce() + Send + 'static>(self, stack: StackToken, child: F) -> Thread {
473        let child: closure::Closure = Box::new(child);
474        let child = Box::into_raw(Box::new(closure::ThreadData {
475            closure: ManuallyDrop::new(child),
476        }));
477        self.init_help(move |raw| {
478            unsafe {
479                k_thread_create(
480                    raw,
481                    stack.base,
482                    stack.size,
483                    Some(closure::child),
484                    child as *mut c_void,
485                    null_mut(),
486                    null_mut(),
487                    5,
488                    0,
489                    K_FOREVER,
490                );
491            }
492        });
493        self.get()
494    }
495}
496
497unsafe extern "C" fn simple_child(
498    arg: *mut c_void,
499    _p2: *mut c_void,
500    _p3: *mut c_void,
501) {
502    let child: fn() -> () = core::mem::transmute(arg);
503    (child)();
504}
505*/
506
507#[cfg(CONFIG_RUST_ALLOC)]
508/// Handle the closure case.  This invokes a double box to rid us of the fat pointer.  I'm not sure
509/// this is actually necessary.
510mod closure {
511    use super::Box;
512    use core::ffi::c_void;
513
514    pub type Closure = Box<dyn FnOnce()>;
515
516    pub struct ThreadData {
517        pub closure: Closure,
518    }
519
520    pub unsafe extern "C" fn child(child: *mut c_void, _p2: *mut c_void, _p3: *mut c_void) {
521        let thread_data: Box<ThreadData> = unsafe { Box::from_raw(child as *mut ThreadData) };
522        let closure = thread_data.closure;
523        closure();
524    }
525}