diff options
Diffstat (limited to 'embassy-executor/src/raw')
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 91 |
1 files changed, 53 insertions, 38 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index e1258ebb5..181dabe8e 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -354,46 +354,54 @@ impl Executor { | |||
| 354 | /// somehow schedule for `poll()` to be called later, at a time you know for sure there's | 354 | /// somehow schedule for `poll()` to be called later, at a time you know for sure there's |
| 355 | /// no `poll()` already running. | 355 | /// no `poll()` already running. |
| 356 | pub unsafe fn poll(&'static self) { | 356 | pub unsafe fn poll(&'static self) { |
| 357 | #[cfg(feature = "integrated-timers")] | 357 | loop { |
| 358 | self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); | 358 | #[cfg(feature = "integrated-timers")] |
| 359 | self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); | ||
| 359 | 360 | ||
| 360 | self.run_queue.dequeue_all(|p| { | 361 | self.run_queue.dequeue_all(|p| { |
| 361 | let task = p.as_ref(); | 362 | let task = p.as_ref(); |
| 362 | 363 | ||
| 363 | #[cfg(feature = "integrated-timers")] | 364 | #[cfg(feature = "integrated-timers")] |
| 364 | task.expires_at.set(Instant::MAX); | 365 | task.expires_at.set(Instant::MAX); |
| 365 | |||
| 366 | let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); | ||
| 367 | if state & STATE_SPAWNED == 0 { | ||
| 368 | // If task is not running, ignore it. This can happen in the following scenario: | ||
| 369 | // - Task gets dequeued, poll starts | ||
| 370 | // - While task is being polled, it gets woken. It gets placed in the queue. | ||
| 371 | // - Task poll finishes, returning done=true | ||
| 372 | // - RUNNING bit is cleared, but the task is already in the queue. | ||
| 373 | return; | ||
| 374 | } | ||
| 375 | 366 | ||
| 376 | #[cfg(feature = "rtos-trace")] | 367 | let state = task.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); |
| 377 | trace::task_exec_begin(p.as_ptr() as u32); | 368 | if state & STATE_SPAWNED == 0 { |
| 369 | // If task is not running, ignore it. This can happen in the following scenario: | ||
| 370 | // - Task gets dequeued, poll starts | ||
| 371 | // - While task is being polled, it gets woken. It gets placed in the queue. | ||
| 372 | // - Task poll finishes, returning done=true | ||
| 373 | // - RUNNING bit is cleared, but the task is already in the queue. | ||
| 374 | return; | ||
| 375 | } | ||
| 378 | 376 | ||
| 379 | // Run the task | 377 | #[cfg(feature = "rtos-trace")] |
| 380 | task.poll_fn.read()(p as _); | 378 | trace::task_exec_begin(p.as_ptr() as u32); |
| 381 | 379 | ||
| 382 | #[cfg(feature = "rtos-trace")] | 380 | // Run the task |
| 383 | trace::task_exec_end(); | 381 | task.poll_fn.read()(p as _); |
| 382 | |||
| 383 | #[cfg(feature = "rtos-trace")] | ||
| 384 | trace::task_exec_end(); | ||
| 385 | |||
| 386 | // Enqueue or update into timer_queue | ||
| 387 | #[cfg(feature = "integrated-timers")] | ||
| 388 | self.timer_queue.update(p); | ||
| 389 | }); | ||
| 384 | 390 | ||
| 385 | // Enqueue or update into timer_queue | ||
| 386 | #[cfg(feature = "integrated-timers")] | 391 | #[cfg(feature = "integrated-timers")] |
| 387 | self.timer_queue.update(p); | 392 | { |
| 388 | }); | 393 | // If this is already in the past, set_alarm might return false |
| 394 | // In that case do another poll loop iteration. | ||
| 395 | let next_expiration = self.timer_queue.next_expiration(); | ||
| 396 | if driver::set_alarm(self.alarm, next_expiration.as_ticks()) { | ||
| 397 | break; | ||
| 398 | } | ||
| 399 | } | ||
| 389 | 400 | ||
| 390 | #[cfg(feature = "integrated-timers")] | 401 | #[cfg(not(feature = "integrated-timers"))] |
| 391 | { | 402 | { |
| 392 | // If this is already in the past, set_alarm will immediately trigger the alarm. | 403 | break; |
| 393 | // This will cause `signal_fn` to be called, which will cause `poll()` to be called again, | 404 | } |
| 394 | // so we immediately do another poll loop iteration. | ||
| 395 | let next_expiration = self.timer_queue.next_expiration(); | ||
| 396 | driver::set_alarm(self.alarm, next_expiration.as_ticks()); | ||
| 397 | } | 405 | } |
| 398 | 406 | ||
| 399 | #[cfg(feature = "rtos-trace")] | 407 | #[cfg(feature = "rtos-trace")] |
| @@ -436,14 +444,21 @@ pub unsafe fn wake_task(task: NonNull<TaskHeader>) { | |||
| 436 | } | 444 | } |
| 437 | 445 | ||
| 438 | #[cfg(feature = "integrated-timers")] | 446 | #[cfg(feature = "integrated-timers")] |
| 439 | #[no_mangle] | 447 | struct TimerQueue; |
| 440 | unsafe fn _embassy_time_schedule_wake(at: Instant, waker: &core::task::Waker) { | 448 | |
| 441 | let task = waker::task_from_waker(waker); | 449 | #[cfg(feature = "integrated-timers")] |
| 442 | let task = task.as_ref(); | 450 | impl embassy_time::queue::TimerQueue for TimerQueue { |
| 443 | let expires_at = task.expires_at.get(); | 451 | fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) { |
| 444 | task.expires_at.set(expires_at.min(at)); | 452 | let task = waker::task_from_waker(waker); |
| 453 | let task = unsafe { task.as_ref() }; | ||
| 454 | let expires_at = task.expires_at.get(); | ||
| 455 | task.expires_at.set(expires_at.min(at)); | ||
| 456 | } | ||
| 445 | } | 457 | } |
| 446 | 458 | ||
| 459 | #[cfg(feature = "integrated-timers")] | ||
| 460 | embassy_time::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); | ||
| 461 | |||
| 447 | #[cfg(feature = "rtos-trace")] | 462 | #[cfg(feature = "rtos-trace")] |
| 448 | impl rtos_trace::RtosTraceOSCallbacks for Executor { | 463 | impl rtos_trace::RtosTraceOSCallbacks for Executor { |
| 449 | fn task_list() { | 464 | fn task_list() { |
