aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/raw/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/raw/mod.rs')
-rw-r--r--embassy-executor/src/raw/mod.rs68
1 files changed, 40 insertions, 28 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 6783c4853..e93e60362 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -141,25 +141,14 @@ impl<F: Future + 'static> TaskStorage<F> {
141 /// Once the task has finished running, you may spawn it again. It is allowed to spawn it 141 /// Once the task has finished running, you may spawn it again. It is allowed to spawn it
142 /// on a different executor. 142 /// on a different executor.
143 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { 143 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> {
144 if self.spawn_mark_used() { 144 let task = AvailableTask::claim(self);
145 return unsafe { SpawnToken::<F>::new(self.spawn_initialize(future)) }; 145 match task {
146 Some(task) => {
147 let task = task.initialize(future);
148 unsafe { SpawnToken::<F>::new(task) }
149 }
150 None => SpawnToken::new_failed(),
146 } 151 }
147
148 SpawnToken::<F>::new_failed()
149 }
150
151 fn spawn_mark_used(&'static self) -> bool {
152 let state = STATE_SPAWNED | STATE_RUN_QUEUED;
153 self.raw
154 .state
155 .compare_exchange(0, state, Ordering::AcqRel, Ordering::Acquire)
156 .is_ok()
157 }
158
159 unsafe fn spawn_initialize(&'static self, future: impl FnOnce() -> F) -> TaskRef {
160 // Initialize the task
161 self.future.write(future());
162 TaskRef::new(self)
163 } 152 }
164 153
165 unsafe fn poll(p: TaskRef) { 154 unsafe fn poll(p: TaskRef) {
@@ -184,6 +173,27 @@ impl<F: Future + 'static> TaskStorage<F> {
184 173
185unsafe impl<F: Future + 'static> Sync for TaskStorage<F> {} 174unsafe impl<F: Future + 'static> Sync for TaskStorage<F> {}
186 175
176struct AvailableTask<F: Future + 'static> {
177 task: &'static TaskStorage<F>,
178}
179
180impl<F: Future + 'static> AvailableTask<F> {
181 fn claim(task: &'static TaskStorage<F>) -> Option<Self> {
182 task.raw
183 .state
184 .compare_exchange(0, STATE_SPAWNED | STATE_RUN_QUEUED, Ordering::AcqRel, Ordering::Acquire)
185 .ok()
186 .map(|_| Self { task })
187 }
188
189 fn initialize(self, future: impl FnOnce() -> F) -> TaskRef {
190 unsafe {
191 self.task.future.write(future());
192 }
193 TaskRef::new(self.task)
194 }
195}
196
187/// Raw storage that can hold up to N tasks of the same type. 197/// Raw storage that can hold up to N tasks of the same type.
188/// 198///
189/// This is essentially a `[TaskStorage<F>; N]`. 199/// This is essentially a `[TaskStorage<F>; N]`.
@@ -207,13 +217,14 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
207 /// is currently free. If none is free, a "poisoned" SpawnToken is returned, 217 /// is currently free. If none is free, a "poisoned" SpawnToken is returned,
208 /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error. 218 /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error.
209 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { 219 pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> {
210 for task in &self.pool { 220 let task = self.pool.iter().find_map(AvailableTask::claim);
211 if task.spawn_mark_used() { 221 match task {
212 return unsafe { SpawnToken::<F>::new(task.spawn_initialize(future)) }; 222 Some(task) => {
223 let task = task.initialize(future);
224 unsafe { SpawnToken::<F>::new(task) }
213 } 225 }
226 None => SpawnToken::new_failed(),
214 } 227 }
215
216 SpawnToken::<F>::new_failed()
217 } 228 }
218 229
219 /// Like spawn(), but allows the task to be send-spawned if the args are Send even if 230 /// Like spawn(), but allows the task to be send-spawned if the args are Send even if
@@ -255,13 +266,14 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
255 // This ONLY holds for `async fn` futures. The other `spawn` methods can be called directly 266 // This ONLY holds for `async fn` futures. The other `spawn` methods can be called directly
256 // by the user, with arbitrary hand-implemented futures. This is why these return `SpawnToken<F>`. 267 // by the user, with arbitrary hand-implemented futures. This is why these return `SpawnToken<F>`.
257 268
258 for task in &self.pool { 269 let task = self.pool.iter().find_map(AvailableTask::claim);
259 if task.spawn_mark_used() { 270 match task {
260 return SpawnToken::<FutFn>::new(task.spawn_initialize(future)); 271 Some(task) => {
272 let task = task.initialize(future);
273 unsafe { SpawnToken::<FutFn>::new(task) }
261 } 274 }
275 None => SpawnToken::new_failed(),
262 } 276 }
263
264 SpawnToken::<FutFn>::new_failed()
265 } 277 }
266} 278}
267 279