aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-04-26 19:08:18 +0200
committerDario Nieuwenhuis <[email protected]>2022-04-26 19:08:18 +0200
commit9e897cbea92dc9b99a65802cc4e0661919001be1 (patch)
treef68a158905b69141a2595693e500a75f5b055b31
parenta39d796c3de9c96ea4df6b9da525cb0d5ef60fc0 (diff)
executor: Add `Spawner::for_current_executor`.
-rw-r--r--embassy/src/executor/arch/cortex_m.rs3
-rw-r--r--embassy/src/executor/spawner.rs62
-rw-r--r--examples/nrf/src/bin/self_spawn_current_executor.rs24
3 files changed, 85 insertions, 4 deletions
diff --git a/embassy/src/executor/arch/cortex_m.rs b/embassy/src/executor/arch/cortex_m.rs
index 87c9c3c87..16f290083 100644
--- a/embassy/src/executor/arch/cortex_m.rs
+++ b/embassy/src/executor/arch/cortex_m.rs
@@ -115,6 +115,9 @@ impl<I: Interrupt> InterruptExecutor<I> {
115 /// different "thread" (the interrupt), so spawning tasks on it is effectively 115 /// different "thread" (the interrupt), so spawning tasks on it is effectively
116 /// sending them. 116 /// sending them.
117 /// 117 ///
118 /// To obtain a [`Spawner`] for this executor, use [`Spawner::for_current_executor`] from
119 /// a task running in it.
120 ///
118 /// This function requires `&'static mut self`. This means you have to store the 121 /// This function requires `&'static mut self`. This means you have to store the
119 /// Executor instance in a place where it'll live forever and grants you mutable 122 /// Executor instance in a place where it'll live forever and grants you mutable
120 /// access. There's a few ways to do this: 123 /// access. There's a few ways to do this:
diff --git a/embassy/src/executor/spawner.rs b/embassy/src/executor/spawner.rs
index d1e4ff17d..e6770e299 100644
--- a/embassy/src/executor/spawner.rs
+++ b/embassy/src/executor/spawner.rs
@@ -1,6 +1,8 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::mem; 2use core::mem;
3use core::ptr::NonNull; 3use core::ptr::NonNull;
4use core::task::Poll;
5use futures::future::poll_fn;
4 6
5use super::raw; 7use super::raw;
6 8
@@ -75,6 +77,23 @@ impl Spawner {
75 } 77 }
76 } 78 }
77 79
80 /// Get a Spawner for the current executor.
81 ///
82 /// This function is `async` just to get access to the current async
83 /// context. It returns instantly, it does not block/yield.
84 ///
85 /// # Panics
86 ///
87 /// Panics if the current executor is not an Embassy executor.
88 pub async fn for_current_executor() -> Self {
89 poll_fn(|cx| unsafe {
90 let task = raw::task_from_waker(cx.waker());
91 let executor = (&*task.as_ptr()).executor.get();
92 Poll::Ready(Self::new(&*executor))
93 })
94 .await
95 }
96
78 /// Spawn a task into an executor. 97 /// Spawn a task into an executor.
79 /// 98 ///
80 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy::task]`). 99 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy::task]`).
@@ -91,10 +110,15 @@ impl Spawner {
91 } 110 }
92 } 111 }
93 112
94 /// Used by the `embassy_macros::main!` macro to throw an error when spawn 113 // Used by the `embassy_macros::main!` macro to throw an error when spawn
95 /// fails. This is here to allow conditional use of `defmt::unwrap!` 114 // fails. This is here to allow conditional use of `defmt::unwrap!`
96 /// without introducing a `defmt` feature in the `embassy_macros` package, 115 // without introducing a `defmt` feature in the `embassy_macros` package,
97 /// which would require use of `-Z namespaced-features`. 116 // which would require use of `-Z namespaced-features`.
117 /// Spawn a task into an executor, panicking on failure.
118 ///
119 /// # Panics
120 ///
121 /// Panics if the spawning fails.
98 pub fn must_spawn<F>(&self, token: SpawnToken<F>) { 122 pub fn must_spawn<F>(&self, token: SpawnToken<F>) {
99 unwrap!(self.spawn(token)); 123 unwrap!(self.spawn(token));
100 } 124 }
@@ -125,6 +149,27 @@ unsafe impl Send for SendSpawner {}
125unsafe impl Sync for SendSpawner {} 149unsafe impl Sync for SendSpawner {}
126 150
127impl SendSpawner { 151impl SendSpawner {
152 pub(crate) fn new(executor: &'static raw::Executor) -> Self {
153 Self { executor }
154 }
155
156 /// Get a Spawner for the current executor.
157 ///
158 /// This function is `async` just to get access to the current async
159 /// context. It returns instantly, it does not block/yield.
160 ///
161 /// # Panics
162 ///
163 /// Panics if the current executor is not an Embassy executor.
164 pub async fn for_current_executor() -> Self {
165 poll_fn(|cx| unsafe {
166 let task = raw::task_from_waker(cx.waker());
167 let executor = (&*task.as_ptr()).executor.get();
168 Poll::Ready(Self::new(&*executor))
169 })
170 .await
171 }
172
128 /// Spawn a task into an executor. 173 /// Spawn a task into an executor.
129 /// 174 ///
130 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy::task]`). 175 /// You obtain the `token` by calling a task function (i.e. one marked with `#[embassy::task]`).
@@ -140,4 +185,13 @@ impl SendSpawner {
140 None => Err(SpawnError::Busy), 185 None => Err(SpawnError::Busy),
141 } 186 }
142 } 187 }
188
189 /// Spawn a task into an executor, panicking on failure.
190 ///
191 /// # Panics
192 ///
193 /// Panics if the spawning fails.
194 pub fn must_spawn<F: Send>(&self, token: SpawnToken<F>) {
195 unwrap!(self.spawn(token));
196 }
143} 197}
diff --git a/examples/nrf/src/bin/self_spawn_current_executor.rs b/examples/nrf/src/bin/self_spawn_current_executor.rs
new file mode 100644
index 000000000..4850d295d
--- /dev/null
+++ b/examples/nrf/src/bin/self_spawn_current_executor.rs
@@ -0,0 +1,24 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy::executor::Spawner;
7use embassy::time::{Duration, Timer};
8use embassy_nrf::Peripherals;
9
10use defmt_rtt as _; // global logger
11use panic_probe as _;
12
13#[embassy::task(pool_size = 2)]
14async fn my_task(n: u32) {
15 Timer::after(Duration::from_secs(1)).await;
16 info!("Spawning self! {}", n);
17 unwrap!(Spawner::for_current_executor().await.spawn(my_task(n + 1)));
18}
19
20#[embassy::main]
21async fn main(spawner: Spawner, _p: Peripherals) {
22 info!("Hello World!");
23 unwrap!(spawner.spawn(my_task(0)));
24}