diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs index 396ce18f..c450982c 100644 --- a/embassy-macros/src/macros/task.rs +++ b/embassy-macros/src/macros/task.rs @@ -76,14 +76,11 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result #embassy_path::executor::SpawnToken { use ::core::future::Future; use #embassy_path::executor::SpawnToken; - use #embassy_path::executor::raw::TaskStorage; + use #embassy_path::executor::raw::TaskPool; type Fut = impl Future + 'static; - #[allow(clippy::declare_interior_mutable_const)] - const NEW_TS: TaskStorage = TaskStorage::new(); - - static POOL: [TaskStorage; #pool_size] = [NEW_TS; #pool_size]; + static POOL: TaskPool = TaskPool::new(); // Opaque type laundering, to obscure its origin! // Workaround for "opaque type's hidden type cannot be another opaque type from the same scope" @@ -92,7 +89,7 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result { raw: TaskHeader, @@ -129,6 +129,9 @@ pub struct TaskStorage { } impl TaskStorage { + #[cfg(feature = "nightly")] + const NEW: Self = Self::new(); + /// Create a new TaskStorage, in not-spawned state. #[cfg(feature = "nightly")] pub const fn new() -> Self { @@ -147,22 +150,6 @@ impl TaskStorage { } } - /// Try to spawn a task in a pool. - /// - /// See [`Self::spawn()`] for details. - /// - /// This will loop over the pool and spawn the task in the first storage that - /// is currently free. If none is free, - pub fn spawn_pool(pool: &'static [Self], future: impl FnOnce() -> F) -> SpawnToken { - for task in pool { - if task.spawn_allocate() { - return unsafe { task.spawn_initialize(future) }; - } - } - - SpawnToken::new_failed() - } - /// Try to spawn the task. /// /// The `future` closure constructs the future. It's only called if spawning is @@ -222,6 +209,41 @@ impl TaskStorage { unsafe impl Sync for TaskStorage {} +/// Raw storage that can hold up to N tasks of the same type. +/// +/// This is essentially a `[TaskStorage; N]`. +#[cfg(feature = "nightly")] +pub struct TaskPool { + pool: [TaskStorage; N], +} + +#[cfg(feature = "nightly")] +impl TaskPool { + /// Create a new TaskPool, with all tasks in non-spawned state. + pub const fn new() -> Self { + Self { + pool: [TaskStorage::NEW; N], + } + } + + /// Try to spawn a task in the pool. + /// + /// See [`TaskStorage::spawn()`] for details. + /// + /// This will loop over the pool and spawn the task in the first storage that + /// is currently free. If none is free, a "poisoned" SpawnToken is returned, + /// which will cause [`Executor::spawn()`] to return the error. + pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken { + for task in &self.pool { + if task.spawn_allocate() { + return unsafe { task.spawn_initialize(future) }; + } + } + + SpawnToken::new_failed() + } +} + /// Raw executor. /// /// This is the core of the Embassy executor. It is low-level, requiring manual