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