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}