diff options
Diffstat (limited to 'embassy-executor/src/raw')
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 88 |
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)] |
| 295 | pub(crate) enum PenderInner { | 295 | pub(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 | |||
| 304 | unsafe impl Send for PenderInner {} | ||
| 305 | unsafe impl Sync for PenderInner {} | ||
| 306 | 296 | ||
| 307 | /// Platform/architecture-specific action executed when an executor has pending work. | 297 | unsafe impl Send for Pender {} |
| 308 | /// | 298 | unsafe 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. | ||
| 314 | pub struct Pender(pub(crate) PenderInner); | ||
| 315 | 299 | ||
| 316 | impl Pender { | 300 | impl 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 | |||
| 332 | impl 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)] |
| 485 | pub struct Executor { | 465 | pub 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) { |
