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
|
/// different "thread" (the interrupt), so spawning tasks on it is effectively
|
||||||
/// sending them.
|
/// 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
|
/// 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
|
/// Executor instance in a place where it'll live forever and grants you mutable
|
||||||
/// access. There's a few ways to do this:
|
/// access. There's a few ways to do this:
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
use core::task::Poll;
|
||||||
|
use futures::future::poll_fn;
|
||||||
|
|
||||||
use super::raw;
|
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.
|
/// Spawn a task into an executor.
|
||||||
///
|
///
|
||||||
/// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy::task]`).
|
/// 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
|
// Used by the `embassy_macros::main!` macro to throw an error when spawn
|
||||||
/// fails. This is here to allow conditional use of `defmt::unwrap!`
|
// fails. This is here to allow conditional use of `defmt::unwrap!`
|
||||||
/// without introducing a `defmt` feature in the `embassy_macros` package,
|
// without introducing a `defmt` feature in the `embassy_macros` package,
|
||||||
/// which would require use of `-Z namespaced-features`.
|
// 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>) {
|
pub fn must_spawn<F>(&self, token: SpawnToken<F>) {
|
||||||
unwrap!(self.spawn(token));
|
unwrap!(self.spawn(token));
|
||||||
}
|
}
|
||||||
|
@ -125,6 +149,27 @@ unsafe impl Send for SendSpawner {}
|
||||||
unsafe impl Sync for SendSpawner {}
|
unsafe impl Sync for SendSpawner {}
|
||||||
|
|
||||||
impl 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.
|
/// Spawn a task into an executor.
|
||||||
///
|
///
|
||||||
/// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy::task]`).
|
/// 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),
|
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