diff options
| author | Dániel Buga <[email protected]> | 2023-08-12 16:00:18 +0200 |
|---|---|---|
| committer | Dániel Buga <[email protected]> | 2023-08-12 18:29:56 +0200 |
| commit | 675b7fb6056d8c3dfaca759b7cd373e2f4a0e111 (patch) | |
| tree | ef4f786edd849f9ce82cffa3b1d58e939a4f53a7 /embassy-executor/src/arch/std.rs | |
| parent | 0727f8690c4684d0622547edee2cf9dc22215a9b (diff) | |
POC: allow custom executors
Diffstat (limited to 'embassy-executor/src/arch/std.rs')
| -rw-r--r-- | embassy-executor/src/arch/std.rs | 74 |
1 files changed, 29 insertions, 45 deletions
diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index 4e4a178f0..28e25fbd0 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | #[cfg(feature = "executor-interrupt")] | 1 | #[cfg(feature = "executor-interrupt")] |
| 2 | compile_error!("`executor-interrupt` is not supported with `arch-std`."); | 2 | compile_error!("`executor-interrupt` is not supported with `arch-std`."); |
| 3 | 3 | ||
| 4 | #[cfg(not(feature = "thread-context"))] | ||
| 5 | compile_error!("`arch-std` requires `thread-context`."); | ||
| 6 | |||
| 4 | #[cfg(feature = "executor-thread")] | 7 | #[cfg(feature = "executor-thread")] |
| 5 | pub use thread::*; | 8 | pub use thread::*; |
| 6 | #[cfg(feature = "executor-thread")] | 9 | #[cfg(feature = "executor-thread")] |
| @@ -11,65 +14,42 @@ mod thread { | |||
| 11 | #[cfg(feature = "nightly")] | 14 | #[cfg(feature = "nightly")] |
| 12 | pub use embassy_macros::main_std as main; | 15 | pub use embassy_macros::main_std as main; |
| 13 | 16 | ||
| 14 | use crate::raw::{Pender, PenderInner}; | 17 | use crate::raw::OpaqueThreadContext; |
| 15 | use crate::{raw, Spawner}; | 18 | use crate::thread::ThreadContext; |
| 16 | |||
| 17 | #[derive(Copy, Clone)] | ||
| 18 | pub(crate) struct ThreadPender(&'static Signaler); | ||
| 19 | |||
| 20 | impl ThreadPender { | ||
| 21 | #[allow(unused)] | ||
| 22 | pub(crate) fn pend(self) { | ||
| 23 | self.0.signal() | ||
| 24 | } | ||
| 25 | } | ||
| 26 | 19 | ||
| 27 | /// Single-threaded std-based executor. | 20 | /// TODO |
| 28 | pub struct Executor { | 21 | // Name pending |
| 29 | inner: raw::Executor, | 22 | pub struct StdThreadCtx { |
| 30 | not_send: PhantomData<*mut ()>, | 23 | _not_send: PhantomData<*mut ()>, |
| 31 | signaler: &'static Signaler, | 24 | signaler: &'static Signaler, |
| 32 | } | 25 | } |
| 33 | 26 | ||
| 34 | impl Executor { | 27 | impl Default for StdThreadCtx { |
| 35 | /// Create a new Executor. | 28 | fn default() -> Self { |
| 36 | pub fn new() -> Self { | ||
| 37 | let signaler = &*Box::leak(Box::new(Signaler::new())); | 29 | let signaler = &*Box::leak(Box::new(Signaler::new())); |
| 38 | Self { | 30 | Self { |
| 39 | inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(signaler)))), | 31 | _not_send: PhantomData, |
| 40 | not_send: PhantomData, | ||
| 41 | signaler, | 32 | signaler, |
| 42 | } | 33 | } |
| 43 | } | 34 | } |
| 35 | } | ||
| 44 | 36 | ||
| 45 | /// Run the executor. | 37 | impl ThreadContext for StdThreadCtx { |
| 46 | /// | 38 | fn context(&self) -> OpaqueThreadContext { |
| 47 | /// The `init` closure is called with a [`Spawner`] that spawns tasks on | 39 | OpaqueThreadContext(self.signaler as *const _ as usize) |
| 48 | /// this executor. Use it to spawn the initial task(s). After `init` returns, | 40 | } |
| 49 | /// the executor starts running the tasks. | ||
| 50 | /// | ||
| 51 | /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), | ||
| 52 | /// for example by passing it as an argument to the initial tasks. | ||
| 53 | /// | ||
| 54 | /// This function requires `&'static mut self`. This means you have to store the | ||
| 55 | /// Executor instance in a place where it'll live forever and grants you mutable | ||
| 56 | /// access. There's a few ways to do this: | ||
| 57 | /// | ||
| 58 | /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) | ||
| 59 | /// - a `static mut` (unsafe) | ||
| 60 | /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) | ||
| 61 | /// | ||
| 62 | /// This function never returns. | ||
| 63 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | ||
| 64 | init(self.inner.spawner()); | ||
| 65 | 41 | ||
| 66 | loop { | 42 | fn wait(&mut self) { |
| 67 | unsafe { self.inner.poll() }; | 43 | self.signaler.wait() |
| 68 | self.signaler.wait() | ||
| 69 | } | ||
| 70 | } | 44 | } |
| 71 | } | 45 | } |
| 72 | 46 | ||
| 47 | #[export_name = "__thread_mode_pender"] | ||
| 48 | fn __thread_mode_pender(core_id: OpaqueThreadContext) { | ||
| 49 | let signaler: &'static Signaler = unsafe { std::mem::transmute(core_id) }; | ||
| 50 | signaler.signal() | ||
| 51 | } | ||
| 52 | |||
| 73 | struct Signaler { | 53 | struct Signaler { |
| 74 | mutex: Mutex<bool>, | 54 | mutex: Mutex<bool>, |
| 75 | condvar: Condvar, | 55 | condvar: Condvar, |
| @@ -97,4 +77,8 @@ mod thread { | |||
| 97 | self.condvar.notify_one(); | 77 | self.condvar.notify_one(); |
| 98 | } | 78 | } |
| 99 | } | 79 | } |
| 80 | |||
| 81 | /// TODO | ||
| 82 | // Type alias for backwards compatibility | ||
| 83 | pub type Executor = crate::thread::ThreadModeExecutor<StdThreadCtx>; | ||
| 100 | } | 84 | } |
