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.rs88
1 files changed, 34 insertions, 54 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 25c2ab0da..7caa3302f 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -292,53 +292,17 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
292} 292}
293 293
294#[derive(Clone, Copy)] 294#[derive(Clone, Copy)]
295pub(crate) enum PenderInner { 295pub(crate) struct Pender(*mut ());
296 #[cfg(feature = "executor-thread")]
297 Thread(crate::arch::ThreadPender),
298 #[cfg(feature = "executor-interrupt")]
299 Interrupt(crate::arch::InterruptPender),
300 #[cfg(feature = "pender-callback")]
301 Callback { func: fn(*mut ()), context: *mut () },
302}
303
304unsafe impl Send for PenderInner {}
305unsafe impl Sync for PenderInner {}
306 296
307/// Platform/architecture-specific action executed when an executor has pending work. 297unsafe impl Send for Pender {}
308/// 298unsafe impl Sync for Pender {}
309/// When a task within an executor is woken, the `Pender` is called. This does a
310/// platform/architecture-specific action to signal there is pending work in the executor.
311/// When this happens, you must arrange for [`Executor::poll`] to be called.
312///
313/// You can think of it as a waker, but for the whole executor.
314pub struct Pender(pub(crate) PenderInner);
315 299
316impl Pender { 300impl Pender {
317 /// Create a `Pender` that will call an arbitrary function pointer. 301 pub(crate) fn pend(self) {
318 /// 302 extern "Rust" {
319 /// # Arguments 303 fn __pender(context: *mut ());
320 ///
321 /// - `func`: The function pointer to call.
322 /// - `context`: Opaque context pointer, that will be passed to the function pointer.
323 #[cfg(feature = "pender-callback")]
324 pub fn new_from_callback(func: fn(*mut ()), context: *mut ()) -> Self {
325 Self(PenderInner::Callback {
326 func,
327 context: context.into(),
328 })
329 }
330}
331
332impl Pender {
333 pub(crate) fn pend(&self) {
334 match self.0 {
335 #[cfg(feature = "executor-thread")]
336 PenderInner::Thread(x) => x.pend(),
337 #[cfg(feature = "executor-interrupt")]
338 PenderInner::Interrupt(x) => x.pend(),
339 #[cfg(feature = "pender-callback")]
340 PenderInner::Callback { func, context } => func(context),
341 } 304 }
305 unsafe { __pender(self.0) };
342 } 306 }
343} 307}
344 308
@@ -472,15 +436,31 @@ impl SyncExecutor {
472/// 436///
473/// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks 437/// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks
474/// that "want to run"). 438/// that "want to run").
475/// - You must supply a [`Pender`]. The executor will call it to notify you it has work 439/// - You must supply a pender function, as shown below. The executor will call it to notify you
476/// to do. You must arrange for `poll()` to be called as soon as possible. 440/// it has work to do. You must arrange for `poll()` to be called as soon as possible.
441/// - Enabling `arch-xx` features will define a pender function for you. This means that you
442/// are limited to using the executors provided to you by the architecture/platform
443/// implementation. If you need a different executor, you must not enable `arch-xx` features.
477/// 444///
478/// The [`Pender`] can be called from *any* context: any thread, any interrupt priority 445/// The pender can be called from *any* context: any thread, any interrupt priority
479/// level, etc. It may be called synchronously from any `Executor` method call as well. 446/// level, etc. It may be called synchronously from any `Executor` method call as well.
480/// You must deal with this correctly. 447/// You must deal with this correctly.
481/// 448///
482/// In particular, you must NOT call `poll` directly from the pender callback, as this violates 449/// In particular, you must NOT call `poll` directly from the pender callback, as this violates
483/// the requirement for `poll` to not be called reentrantly. 450/// the requirement for `poll` to not be called reentrantly.
451///
452/// The pender function must be exported with the name `__pender` and have the following signature:
453///
454/// ```rust
455/// #[export_name = "__pender"]
456/// fn pender(context: *mut ()) {
457/// // schedule `poll()` to be called
458/// }
459/// ```
460///
461/// The `context` argument is a piece of arbitrary data the executor will pass to the pender.
462/// You can set the `context` when calling [`Executor::new()`]. You can use it to, for example,
463/// differentiate between executors, or to pass a pointer to a callback that should be called.
484#[repr(transparent)] 464#[repr(transparent)]
485pub struct Executor { 465pub struct Executor {
486 pub(crate) inner: SyncExecutor, 466 pub(crate) inner: SyncExecutor,
@@ -495,12 +475,12 @@ impl Executor {
495 475
496 /// Create a new executor. 476 /// Create a new executor.
497 /// 477 ///
498 /// When the executor has work to do, it will call the [`Pender`]. 478 /// When the executor has work to do, it will call the pender function and pass `context` to it.
499 /// 479 ///
500 /// See [`Executor`] docs for details on `Pender`. 480 /// See [`Executor`] docs for details on the pender.
501 pub fn new(pender: Pender) -> Self { 481 pub fn new(context: *mut ()) -> Self {
502 Self { 482 Self {
503 inner: SyncExecutor::new(pender), 483 inner: SyncExecutor::new(Pender(context)),
504 _not_sync: PhantomData, 484 _not_sync: PhantomData,
505 } 485 }
506 } 486 }
@@ -523,16 +503,16 @@ impl Executor {
523 /// This loops over all tasks that are queued to be polled (i.e. they're 503 /// This loops over all tasks that are queued to be polled (i.e. they're
524 /// freshly spawned or they've been woken). Other tasks are not polled. 504 /// freshly spawned or they've been woken). Other tasks are not polled.
525 /// 505 ///
526 /// You must call `poll` after receiving a call to the [`Pender`]. It is OK 506 /// You must call `poll` after receiving a call to the pender. It is OK
527 /// to call `poll` even when not requested by the `Pender`, but it wastes 507 /// to call `poll` even when not requested by the pender, but it wastes
528 /// energy. 508 /// energy.
529 /// 509 ///
530 /// # Safety 510 /// # Safety
531 /// 511 ///
532 /// You must NOT call `poll` reentrantly on the same executor. 512 /// You must NOT call `poll` reentrantly on the same executor.
533 /// 513 ///
534 /// In particular, note that `poll` may call the `Pender` synchronously. Therefore, you 514 /// In particular, note that `poll` may call the pender synchronously. Therefore, you
535 /// must NOT directly call `poll()` from the `Pender` callback. Instead, the callback has to 515 /// must NOT directly call `poll()` from the pender callback. Instead, the callback has to
536 /// somehow schedule for `poll()` to be called later, at a time you know for sure there's 516 /// somehow schedule for `poll()` to be called later, at a time you know for sure there's
537 /// no `poll()` already running. 517 /// no `poll()` already running.
538 pub unsafe fn poll(&'static self) { 518 pub unsafe fn poll(&'static self) {