aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/raw
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor/src/raw')
-rw-r--r--embassy-executor/src/raw/mod.rs97
1 files changed, 76 insertions, 21 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 72c367c33..f6c66da5a 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -19,7 +19,6 @@ use core::marker::PhantomData;
19use core::mem; 19use core::mem;
20use core::pin::Pin; 20use core::pin::Pin;
21use core::ptr::NonNull; 21use core::ptr::NonNull;
22use core::sync::atomic::AtomicPtr;
23use core::task::{Context, Poll}; 22use core::task::{Context, Poll};
24 23
25use atomic_polyfill::{AtomicU32, Ordering}; 24use atomic_polyfill::{AtomicU32, Ordering};
@@ -290,10 +289,60 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
290 } 289 }
291} 290}
292 291
292#[derive(Clone, Copy)]
293pub(crate) enum PenderInner {
294 #[cfg(feature = "executor-thread")]
295 Thread(crate::arch::ThreadPender),
296 #[cfg(feature = "executor-interrupt")]
297 Interrupt(crate::arch::InterruptPender),
298 #[cfg(feature = "pender-callback")]
299 Callback { func: fn(*mut ()), context: *mut () },
300}
301
302unsafe impl Send for PenderInner {}
303unsafe impl Sync for PenderInner {}
304
305/// Platform/architecture-specific action executed when an executor has pending work.
306///
307/// When a task within an executor is woken, the `Pender` is called. This does a
308/// platform/architecture-specific action to signal there is pending work in the executor.
309/// When this happens, you must arrange for [`Executor::poll`] to be called.
310///
311/// You can think of it as a waker, but for the whole executor.
312pub struct Pender(pub(crate) PenderInner);
313
314impl Pender {
315 /// Create a `Pender` that will call an arbitrary function pointer.
316 ///
317 /// # Arguments
318 ///
319 /// - `func`: The function pointer to call.
320 /// - `context`: Opaque context pointer, that will be passed to the function pointer.
321 #[cfg(feature = "pender-callback")]
322 pub fn new_from_callback(func: fn(*mut ()), context: *mut ()) -> Self {
323 Self(PenderInner::Callback {
324 func,
325 context: context.into(),
326 })
327 }
328}
329
330impl Pender {
331 pub(crate) fn pend(&self) {
332 match self.0 {
333 #[cfg(feature = "executor-thread")]
334 PenderInner::Thread(x) => x.pend(),
335 #[cfg(feature = "executor-interrupt")]
336 PenderInner::Interrupt(x) => x.pend(),
337 #[cfg(feature = "pender-callback")]
338 PenderInner::Callback { func, context } => func(context),
339 }
340 }
341}
342
293pub(crate) struct SyncExecutor { 343pub(crate) struct SyncExecutor {
294 run_queue: RunQueue, 344 run_queue: RunQueue,
295 signal_fn: fn(*mut ()), 345 pender: Pender,
296 signal_ctx: AtomicPtr<()>,
297 346
298 #[cfg(feature = "integrated-timers")] 347 #[cfg(feature = "integrated-timers")]
299 pub(crate) timer_queue: timer_queue::TimerQueue, 348 pub(crate) timer_queue: timer_queue::TimerQueue,
@@ -302,16 +351,13 @@ pub(crate) struct SyncExecutor {
302} 351}
303 352
304impl SyncExecutor { 353impl SyncExecutor {
305 pub(crate) fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self { 354 pub(crate) fn new(pender: Pender) -> Self {
306 #[cfg(feature = "integrated-timers")] 355 #[cfg(feature = "integrated-timers")]
307 let alarm = unsafe { unwrap!(driver::allocate_alarm()) }; 356 let alarm = unsafe { unwrap!(driver::allocate_alarm()) };
308 #[cfg(feature = "integrated-timers")]
309 driver::set_alarm_callback(alarm, signal_fn, signal_ctx);
310 357
311 Self { 358 Self {
312 run_queue: RunQueue::new(), 359 run_queue: RunQueue::new(),
313 signal_fn, 360 pender,
314 signal_ctx: AtomicPtr::new(signal_ctx),
315 361
316 #[cfg(feature = "integrated-timers")] 362 #[cfg(feature = "integrated-timers")]
317 timer_queue: timer_queue::TimerQueue::new(), 363 timer_queue: timer_queue::TimerQueue::new(),
@@ -332,10 +378,16 @@ impl SyncExecutor {
332 trace::task_ready_begin(task.as_ptr() as u32); 378 trace::task_ready_begin(task.as_ptr() as u32);
333 379
334 if self.run_queue.enqueue(cs, task) { 380 if self.run_queue.enqueue(cs, task) {
335 (self.signal_fn)(self.signal_ctx.load(Ordering::Relaxed)) 381 self.pender.pend();
336 } 382 }
337 } 383 }
338 384
385 #[cfg(feature = "integrated-timers")]
386 fn alarm_callback(ctx: *mut ()) {
387 let this: &Self = unsafe { &*(ctx as *const Self) };
388 this.pender.pend();
389 }
390
339 pub(super) unsafe fn spawn(&'static self, task: TaskRef) { 391 pub(super) unsafe fn spawn(&'static self, task: TaskRef) {
340 task.header().executor.set(Some(self)); 392 task.header().executor.set(Some(self));
341 393
@@ -351,6 +403,9 @@ impl SyncExecutor {
351 /// 403 ///
352 /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. 404 /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created.
353 pub(crate) unsafe fn poll(&'static self) { 405 pub(crate) unsafe fn poll(&'static self) {
406 #[cfg(feature = "integrated-timers")]
407 driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ());
408
354 #[allow(clippy::never_loop)] 409 #[allow(clippy::never_loop)]
355 loop { 410 loop {
356 #[cfg(feature = "integrated-timers")] 411 #[cfg(feature = "integrated-timers")]
@@ -417,14 +472,14 @@ impl SyncExecutor {
417/// 472///
418/// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks 473/// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks
419/// that "want to run"). 474/// that "want to run").
420/// - You must supply a `signal_fn`. The executor will call it to notify you it has work 475/// - You must supply a [`Pender`]. The executor will call it to notify you it has work
421/// to do. You must arrange for `poll()` to be called as soon as possible. 476/// to do. You must arrange for `poll()` to be called as soon as possible.
422/// 477///
423/// `signal_fn` can be called from *any* context: any thread, any interrupt priority 478/// The [`Pender`] can be called from *any* context: any thread, any interrupt priority
424/// level, etc. It may be called synchronously from any `Executor` method call as well. 479/// level, etc. It may be called synchronously from any `Executor` method call as well.
425/// You must deal with this correctly. 480/// You must deal with this correctly.
426/// 481///
427/// In particular, you must NOT call `poll` directly from `signal_fn`, as this violates 482/// In particular, you must NOT call `poll` directly from the pender callback, as this violates
428/// the requirement for `poll` to not be called reentrantly. 483/// the requirement for `poll` to not be called reentrantly.
429#[repr(transparent)] 484#[repr(transparent)]
430pub struct Executor { 485pub struct Executor {
@@ -437,15 +492,15 @@ impl Executor {
437 pub(crate) unsafe fn wrap(inner: &SyncExecutor) -> &Self { 492 pub(crate) unsafe fn wrap(inner: &SyncExecutor) -> &Self {
438 mem::transmute(inner) 493 mem::transmute(inner)
439 } 494 }
495
440 /// Create a new executor. 496 /// Create a new executor.
441 /// 497 ///
442 /// When the executor has work to do, it will call `signal_fn` with 498 /// When the executor has work to do, it will call the [`Pender`].
443 /// `signal_ctx` as argument.
444 /// 499 ///
445 /// See [`Executor`] docs for details on `signal_fn`. 500 /// See [`Executor`] docs for details on `Pender`.
446 pub fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self { 501 pub fn new(pender: Pender) -> Self {
447 Self { 502 Self {
448 inner: SyncExecutor::new(signal_fn, signal_ctx), 503 inner: SyncExecutor::new(pender),
449 _not_sync: PhantomData, 504 _not_sync: PhantomData,
450 } 505 }
451 } 506 }
@@ -468,16 +523,16 @@ impl Executor {
468 /// This loops over all tasks that are queued to be polled (i.e. they're 523 /// This loops over all tasks that are queued to be polled (i.e. they're
469 /// freshly spawned or they've been woken). Other tasks are not polled. 524 /// freshly spawned or they've been woken). Other tasks are not polled.
470 /// 525 ///
471 /// You must call `poll` after receiving a call to `signal_fn`. It is OK 526 /// You must call `poll` after receiving a call to the [`Pender`]. It is OK
472 /// to call `poll` even when not requested by `signal_fn`, but it wastes 527 /// to call `poll` even when not requested by the `Pender`, but it wastes
473 /// energy. 528 /// energy.
474 /// 529 ///
475 /// # Safety 530 /// # Safety
476 /// 531 ///
477 /// You must NOT call `poll` reentrantly on the same executor. 532 /// You must NOT call `poll` reentrantly on the same executor.
478 /// 533 ///
479 /// In particular, note that `poll` may call `signal_fn` synchronously. Therefore, you 534 /// In particular, note that `poll` may call the `Pender` synchronously. Therefore, you
480 /// must NOT directly call `poll()` from your `signal_fn`. Instead, `signal_fn` has to 535 /// must NOT directly call `poll()` from the `Pender` callback. Instead, the callback has to
481 /// somehow schedule for `poll()` to be called later, at a time you know for sure there's 536 /// somehow schedule for `poll()` to be called later, at a time you know for sure there's
482 /// no `poll()` already running. 537 /// no `poll()` already running.
483 pub unsafe fn poll(&'static self) { 538 pub unsafe fn poll(&'static self) {