executor: Add Spawner::for_current_executor
.
This commit is contained in:
parent
a39d796c3d
commit
9e897cbea9
3 changed files with 85 additions and 4 deletions
|
@ -115,6 +115,9 @@ impl<I: Interrupt> InterruptExecutor<I> {
|
|||
/// different "thread" (the interrupt), so spawning tasks on it is effectively
|
||||
/// sending them.
|
||||
///
|
||||
/// To obtain a [`Spawner`] for this executor, use [`Spawner::for_current_executor`] from
|
||||
/// a task running in it.
|
||||
///
|
||||
/// This function requires `&'static mut self`. This means you have to store the
|
||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||
/// access. There's a few ways to do this:
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::ptr::NonNull;
|
||||
use core::task::Poll;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use super::raw;
|
||||
|
||||
|
@ -75,6 +77,23 @@ impl Spawner {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get a Spawner for the current executor.
|
||||
///
|
||||
/// This function is `async` just to get access to the current async
|
||||
/// context. It returns instantly, it does not block/yield.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the current executor is not an Embassy executor.
|
||||
pub async fn for_current_executor() -> Self {
|
||||
poll_fn(|cx| unsafe {
|
||||
let task = raw::task_from_waker(cx.waker());
|
||||
let executor = (&*task.as_ptr()).executor.get();
|
||||
Poll::Ready(Self::new(&*executor))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Spawn a task into an executor.
|
||||
///
|
||||
/// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy::task]`).
|
||||
|
@ -91,10 +110,15 @@ impl Spawner {
|
|||
}
|
||||
}
|
||||
|
||||
/// Used by the `embassy_macros::main!` macro to throw an error when spawn
|
||||
/// fails. This is here to allow conditional use of `defmt::unwrap!`
|
||||
/// without introducing a `defmt` feature in the `embassy_macros` package,
|
||||
/// which would require use of `-Z namespaced-features`.
|
||||
// Used by the `embassy_macros::main!` macro to throw an error when spawn
|
||||
// fails. This is here to allow conditional use of `defmt::unwrap!`
|
||||
// without introducing a `defmt` feature in the `embassy_macros` package,
|
||||
// which would require use of `-Z namespaced-features`.
|
||||
/// Spawn a task into an executor, panicking on failure.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the spawning fails.
|
||||
pub fn must_spawn<F>(&self, token: SpawnToken<F>) {
|
||||
unwrap!(self.spawn(token));
|
||||
}
|
||||
|
@ -125,6 +149,27 @@ unsafe impl Send for SendSpawner {}
|
|||
unsafe impl Sync for SendSpawner {}
|
||||
|
||||
impl SendSpawner {
|
||||
pub(crate) fn new(executor: &'static raw::Executor) -> Self {
|
||||
Self { executor }
|
||||
}
|
||||
|
||||
/// Get a Spawner for the current executor.
|
||||
///
|
||||
/// This function is `async` just to get access to the current async
|
||||
/// context. It returns instantly, it does not block/yield.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the current executor is not an Embassy executor.
|
||||
pub async fn for_current_executor() -> Self {
|
||||
poll_fn(|cx| unsafe {
|
||||
let task = raw::task_from_waker(cx.waker());
|
||||
let executor = (&*task.as_ptr()).executor.get();
|
||||
Poll::Ready(Self::new(&*executor))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Spawn a task into an executor.
|
||||
///
|
||||
/// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy::task]`).
|
||||
|
@ -140,4 +185,13 @@ impl SendSpawner {
|
|||
None => Err(SpawnError::Busy),
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn a task into an executor, panicking on failure.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the spawning fails.
|
||||
pub fn must_spawn<F: Send>(&self, token: SpawnToken<F>) {
|
||||
unwrap!(self.spawn(token));
|
||||
}
|
||||
}
|
||||
|
|
24
examples/nrf/src/bin/self_spawn_current_executor.rs
Normal file
24
examples/nrf/src/bin/self_spawn_current_executor.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use defmt::{info, unwrap};
|
||||
use embassy::executor::Spawner;
|
||||
use embassy::time::{Duration, Timer};
|
||||
use embassy_nrf::Peripherals;
|
||||
|
||||
use defmt_rtt as _; // global logger
|
||||
use panic_probe as _;
|
||||
|
||||
#[embassy::task(pool_size = 2)]
|
||||
async fn my_task(n: u32) {
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
info!("Spawning self! {}", n);
|
||||
unwrap!(Spawner::for_current_executor().await.spawn(my_task(n + 1)));
|
||||
}
|
||||
|
||||
#[embassy::main]
|
||||
async fn main(spawner: Spawner, _p: Peripherals) {
|
||||
info!("Hello World!");
|
||||
unwrap!(spawner.spawn(my_task(0)));
|
||||
}
|
Loading…
Reference in a new issue