126126//!
127127//! ## The work queues themselves
128128//!
129- //! Workqueues themselves are built using [`WorkQueueBuilder`]. This needs a statically defined
130- //! stack. Typical usage will be along the lines of:
131- //! ```rust
132- //! kobj_define! {
133- //! WORKER_STACK: ThreadStack<2048>;
134- //! }
135- //! // ...
136- //! let main_worker = Box::new(
137- //! WorkQueueBuilder::new()
138- //! .set_priority(2).
139- //! .set_name(c"mainloop")
140- //! .set_no_yield(true)
141- //! .start(MAIN_LOOP_STACK.init_once(()).unwrap())
142- //! );
143- //!
144- //! let _ = zephyr::kio::spawn(
145- //! mainloop(), // Async or function returning Future.
146- //! &main_worker,
147- //! c"w:mainloop",
148- //! );
129+ //! Work Queues should be declared with the `define_work_queue!` macro, this macro requires the name
130+ //! of the symbol for the work queue, the stack size, and then zero or more optional arguments,
131+ //! defined by the fields in the [`WorkQueueDeclArgs`] struct. For example:
149132//!
150- //! ...
151- //!
152- //! // Leak the Box so that the worker is never freed.
153- //! let _ = Box::leak(main_worker);
133+ //! ```rust
134+ //! define_work_queue!(MY_WORKQ, 2048, no_yield = true, priority = 2);
154135//! ```
155136//!
156- //! It is important that WorkQueues never be dropped. It has a Drop implementation that invokes
157- //! panic. Zephyr provides no mechanism to stop work queue threads, so dropping would result in
158- //! undefined behavior.
159- //!
160- //! # Current Status
161- //!
162- //! Although Zephyr has 3 types of work queues, the `k_work_poll` is sufficient to implement all of
163- //! the behavior, and this implementation only implements this type. Non Future work could be built
164- //! around the other work types.
165- //!
166- //! As such, this means that manually constructed work is still built using `Future`. The `_async`
167- //! primitives throughout this crate can be used just as readily by hand-written Futures as by async
168- //! code. Notable, the use of [`Signal`] will likely be common, along with possible timeouts.
169- //!
170- //! [`sys::sync::Semaphore`]: crate::sys::sync::Semaphore
171- //! [`sync::channel`]: crate::sync::channel
172- //! [`sync::Mutex`]: crate::sync::Mutex
173- //! [`kio::sync::Mutex`]: crate::kio::sync::Mutex
174- //! [`kio::spawn`]: crate::kio::spawn
175- //! [`join`]: futures::JoinHandle::join
176- //! [`join_async`]: futures::JoinHandle::join_async
137+ //! Then, in code, the work queue can be started, and used to issue work.
138+ //! ```rust
139+ //! let my_workq = MY_WORKQ.start();
140+ //! let action = Work::new(action_item);
141+ //! action.submit(my_workq);
142+ //! ```
177143
178144extern crate alloc;
179145
180146use core:: {
181147 cell:: { RefCell , UnsafeCell } ,
182- ffi:: { c_int, c_uint} ,
148+ ffi:: { c_char , c_int, c_uint} ,
183149 mem,
184150 pin:: Pin ,
185151 sync:: atomic:: Ordering ,
@@ -196,6 +162,30 @@ use zephyr_sys::{
196162
197163use crate :: { error:: to_result_void, object:: Fixed , simpletls:: SimpleTls } ;
198164
165+ /// The WorkQueue decl args as a struct, so we can have a default, and the macro can fill in those
166+ /// specified by the user.
167+ pub struct WorkQueueDeclArgs {
168+ /// Should this work queue call yield after each queued item.
169+ pub no_yield : bool ,
170+ /// Is this work queue thread "essential".
171+ ///
172+ /// Threads marked essential will panic if they stop running.
173+ pub essential : bool ,
174+ /// Zephyr thread priority for the work queue thread.
175+ pub priority : c_int ,
176+ }
177+
178+ impl WorkQueueDeclArgs {
179+ /// Like `Default::default`, but const.
180+ pub const fn default_values ( ) -> Self {
181+ Self {
182+ no_yield : false ,
183+ essential : false ,
184+ priority : 0 ,
185+ }
186+ }
187+ }
188+
199189/// A static declaration of a work-queue. This associates a work queue, with a stack, and an atomic
200190/// to determine if it has been initialized.
201191// TODO: Remove the pub on the fields, and make a constructor.
@@ -215,14 +205,18 @@ impl<const SIZE: usize> WorkQueueDecl<SIZE> {
215205 /// Static constructor. Mostly for use by the macro.
216206 pub const fn new (
217207 stack : & ' static crate :: thread:: ThreadStack < SIZE > ,
218- config : k_work_queue_config ,
219- priority : c_int ,
208+ name : * const c_char ,
209+ args : WorkQueueDeclArgs ,
220210 ) -> Self {
221211 Self {
222212 queue : unsafe { mem:: zeroed ( ) } ,
223213 stack,
224- config,
225- priority,
214+ config : k_work_queue_config {
215+ name,
216+ no_yield : args. no_yield ,
217+ essential : args. essential ,
218+ } ,
219+ priority : args. priority ,
226220 started : AtomicBool :: new ( false ) ,
227221 }
228222 }
@@ -442,6 +436,24 @@ impl SubmitResult {
442436 }
443437}
444438
439+ /*
440+ pub trait Queueable: Send + Sync {
441+ fn as_ptr(&self) -> *const ();
442+ }
443+
444+ impl<T: Send + Sync> Queueable for Arc<T> {
445+ fn as_ptr(&self) -> *const () {
446+ todo!()
447+ }
448+ }
449+
450+ impl<T: Send + Sync> Queueable for &'static T {
451+ fn as_ptr(&self) -> *const () {
452+ todo!()
453+ }
454+ }
455+ */
456+
445457/// A simple action that just does something with its data.
446458///
447459/// This is similar to a Future, except there is no concept of it completing. It manages its
@@ -583,3 +595,32 @@ impl<T: SimpleAction + Send> Work<T> {
583595 & self . action
584596 }
585597}
598+
599+ /// Declare a static work queue.
600+ ///
601+ /// This declares a static work queue (of type [`WorkQueueDecl`]). This will have a single method
602+ /// `.start()` which can be used to start the work queue, as well as return the persistent handle
603+ /// that can be used to enqueue to it.
604+ #[ macro_export]
605+ macro_rules! define_work_queue {
606+ ( $name: ident, $stack_size: expr) => {
607+ $crate:: define_work_queue!( $name, $stack_size, ) ;
608+ } ;
609+ ( $name: ident, $stack_size: expr, $( $key: ident = $value: expr) ,* $( , ) ?) => {
610+ static $name: $crate:: work:: WorkQueueDecl <$stack_size> = {
611+ #[ link_section = concat!( ".noinit.workq." , stringify!( $name) ) ]
612+ static _ZEPHYR_STACK: $crate:: thread:: ThreadStack <$stack_size> =
613+ $crate:: thread:: ThreadStack :: new( ) ;
614+ const _ZEPHYR_C_NAME: & [ u8 ] = concat!( stringify!( $name) , "\0 " ) . as_bytes( ) ;
615+ const _ZEPHYR_ARGS: $crate:: work:: WorkQueueDeclArgs = $crate:: work:: WorkQueueDeclArgs {
616+ $( $key: $value, ) *
617+ ..$crate:: work:: WorkQueueDeclArgs :: default_values( )
618+ } ;
619+ $crate:: work:: WorkQueueDecl :: new(
620+ & _ZEPHYR_STACK,
621+ _ZEPHYR_C_NAME. as_ptr( ) as * const :: core:: ffi:: c_char,
622+ _ZEPHYR_ARGS,
623+ )
624+ } ;
625+ } ;
626+ }
0 commit comments