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}