aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-04-27 03:23:54 +0200
committerDario Nieuwenhuis <[email protected]>2022-04-27 04:56:41 +0200
commit293f54d13406850d24d1226eb77989f4fa8db9f4 (patch)
treec8831ae9d2d046549b3d64294408920b9b8a5597
parentdf814f9bbd5cc03f4d60eb8cb19374d23f0a84a0 (diff)
executor: add raw::TaskPool.
This simplifies the macro code a bit.
-rw-r--r--embassy-macros/src/macros/task.rs9
-rw-r--r--embassy/src/executor/raw/mod.rs56
2 files changed, 42 insertions, 23 deletions
diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs
index 396ce18f2..c450982c9 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<TokenStream, Toke
76 #visibility fn #task_ident(#fargs) -> #embassy_path::executor::SpawnToken<impl ::core::future::Future + 'static> { 76 #visibility fn #task_ident(#fargs) -> #embassy_path::executor::SpawnToken<impl ::core::future::Future + 'static> {
77 use ::core::future::Future; 77 use ::core::future::Future;
78 use #embassy_path::executor::SpawnToken; 78 use #embassy_path::executor::SpawnToken;
79 use #embassy_path::executor::raw::TaskStorage; 79 use #embassy_path::executor::raw::TaskPool;
80 80
81 type Fut = impl Future + 'static; 81 type Fut = impl Future + 'static;
82 82
83 #[allow(clippy::declare_interior_mutable_const)] 83 static POOL: TaskPool<Fut, #pool_size> = TaskPool::new();
84 const NEW_TS: TaskStorage<Fut> = TaskStorage::new();
85
86 static POOL: [TaskStorage<Fut>; #pool_size] = [NEW_TS; #pool_size];
87 84
88 // Opaque type laundering, to obscure its origin! 85 // Opaque type laundering, to obscure its origin!
89 // Workaround for "opaque type's hidden type cannot be another opaque type from the same scope" 86 // 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<TokenStream, Toke
92 token 89 token
93 } 90 }
94 91
95 launder_tait(unsafe { TaskStorage::spawn_pool(&POOL, move || #task_inner_ident(#(#arg_names,)*)) }) 92 launder_tait(POOL.spawn(move || #task_inner_ident(#(#arg_names,)*)))
96 } 93 }
97 }; 94 };
98 95
diff --git a/embassy/src/executor/raw/mod.rs b/embassy/src/executor/raw/mod.rs
index 3ae52ae31..5af35d868 100644
--- a/embassy/src/executor/raw/mod.rs
+++ b/embassy/src/executor/raw/mod.rs
@@ -121,7 +121,7 @@ impl TaskHeader {
121/// the memory for the task is allocated: on the stack, or on the heap with e.g. `Box::leak`, etc. 121/// the memory for the task is allocated: on the stack, or on the heap with e.g. `Box::leak`, etc.
122 122
123// repr(C) is needed to guarantee that the Task is located at offset 0 123// repr(C) is needed to guarantee that the Task is located at offset 0
124// This makes it safe to cast between Task and Task pointers. 124// This makes it safe to cast between TaskHeader and TaskStorage pointers.
125#[repr(C)] 125#[repr(C)]
126pub struct TaskStorage<F: Future + 'static> { 126pub struct TaskStorage<F: Future + 'static> {
127 raw: TaskHeader, 127 raw: TaskHeader,
@@ -129,6 +129,9 @@ pub struct TaskStorage<F: Future + 'static> {
129} 129}
130 130
131impl<F: Future + 'static> TaskStorage<F> { 131impl<F: Future + 'static> TaskStorage<F> {
132 #[cfg(feature = "nightly")]
133 const NEW: Self = Self::new();
134
132 /// Create a new TaskStorage, in not-spawned state. 135 /// Create a new TaskStorage, in not-spawned state.
133 #[cfg(feature = "nightly")] 136 #[cfg(feature = "nightly")]
134 pub const fn new() -> Self { 137 pub const fn new() -> Self {
@@ -147,22 +150,6 @@ impl<F: Future + 'static> TaskStorage<F> {
147 } 150 }
148 } 151 }
149 152
150 /// Try to spawn a task in a pool.
151 ///
152 /// See [`Self::spawn()`] for details.
153 ///
154 /// This will loop over the pool and spawn the task in the first storage that
155 /// is currently free. If none is free,
156 pub fn spawn_pool(pool: &'static [Self], future: impl FnOnce() -> F) -> SpawnToken<F> {
157 for task in pool {
158 if task.spawn_allocate() {
159 return unsafe { task.spawn_initialize(future) };
160 }
161 }
162
163 SpawnToken::new_failed()
164 }
165
166 /// Try to spawn the task. 153 /// Try to spawn the task.
167 /// 154 ///
168 /// The `future` closure constructs the future. It's only called if spawning is 155 /// The `future` closure constructs the future. It's only called if spawning is
@@ -222,6 +209,41 @@ impl<F: Future + 'static> TaskStorage<F> {
222 209
223unsafe impl<F: Future + 'static> Sync for TaskStorage<F> {} 210unsafe impl<F: Future + 'static> Sync for TaskStorage<F> {}
224 211
212/// Raw storage that can hold up to N tasks of the same type.
213///
214/// This is essentially a `[TaskStorage<F>; N]`.
215#[cfg(feature = "nightly")]
216pub struct TaskPool<F: Future + 'static, const N: usize> {
217 pool: [TaskStorage<F>; N],
218}
219
220#[cfg(feature = "nightly")]
221impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
222 /// Create a new TaskPool, with all tasks in non-spawned state.
223 pub const fn new() -> Self {
224 Self {
225 pool: [TaskStorage::NEW; N],
226 }
227 }
228
229 /// Try to spawn a task in the pool.
230 ///
231 /// See [`TaskStorage::spawn()`] for details.
232 ///
233 /// This will loop over the pool and spawn the task in the first storage that
234 /// is currently free. If none is free, a "poisoned" SpawnToken is returned,
235 /// which will cause [`Executor::spawn()`] to return the error.
236 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<F> {
237 for task in &self.pool {
238 if task.spawn_allocate() {
239 return unsafe { task.spawn_initialize(future) };
240 }
241 }
242
243 SpawnToken::new_failed()
244 }
245}
246
225/// Raw executor. 247/// Raw executor.
226/// 248///
227/// This is the core of the Embassy executor. It is low-level, requiring manual 249/// This is the core of the Embassy executor. It is low-level, requiring manual