diff options
Diffstat (limited to 'embassy-executor/src')
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 68 |
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 | ||
| 185 | unsafe impl<F: Future + 'static> Sync for TaskStorage<F> {} | 174 | unsafe impl<F: Future + 'static> Sync for TaskStorage<F> {} |
| 186 | 175 | ||
| 176 | struct AvailableTask<F: Future + 'static> { | ||
| 177 | task: &'static TaskStorage<F>, | ||
| 178 | } | ||
| 179 | |||
| 180 | impl<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 | ||
