diff options
Diffstat (limited to 'embassy-executor/src/arch/std.rs')
| -rw-r--r-- | embassy-executor/src/arch/std.rs | 150 |
1 files changed, 83 insertions, 67 deletions
diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index 701f0eb18..4e4a178f0 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs | |||
| @@ -1,84 +1,100 @@ | |||
| 1 | use std::marker::PhantomData; | 1 | #[cfg(feature = "executor-interrupt")] |
| 2 | use std::sync::{Condvar, Mutex}; | 2 | compile_error!("`executor-interrupt` is not supported with `arch-std`."); |
| 3 | 3 | ||
| 4 | use super::{raw, Spawner}; | 4 | #[cfg(feature = "executor-thread")] |
| 5 | pub use thread::*; | ||
| 6 | #[cfg(feature = "executor-thread")] | ||
| 7 | mod thread { | ||
| 8 | use std::marker::PhantomData; | ||
| 9 | use std::sync::{Condvar, Mutex}; | ||
| 5 | 10 | ||
| 6 | /// Single-threaded std-based executor. | 11 | #[cfg(feature = "nightly")] |
| 7 | pub struct Executor { | 12 | pub use embassy_macros::main_std as main; |
| 8 | inner: raw::Executor, | 13 | |
| 9 | not_send: PhantomData<*mut ()>, | 14 | use crate::raw::{Pender, PenderInner}; |
| 10 | signaler: &'static Signaler, | 15 | use crate::{raw, Spawner}; |
| 11 | } | ||
| 12 | 16 | ||
| 13 | impl Executor { | 17 | #[derive(Copy, Clone)] |
| 14 | /// Create a new Executor. | 18 | pub(crate) struct ThreadPender(&'static Signaler); |
| 15 | pub fn new() -> Self { | 19 | |
| 16 | let signaler = &*Box::leak(Box::new(Signaler::new())); | 20 | impl ThreadPender { |
| 17 | Self { | 21 | #[allow(unused)] |
| 18 | inner: raw::Executor::new( | 22 | pub(crate) fn pend(self) { |
| 19 | |p| unsafe { | 23 | self.0.signal() |
| 20 | let s = &*(p as *const () as *const Signaler); | ||
| 21 | s.signal() | ||
| 22 | }, | ||
| 23 | signaler as *const _ as _, | ||
| 24 | ), | ||
| 25 | not_send: PhantomData, | ||
| 26 | signaler, | ||
| 27 | } | 24 | } |
| 28 | } | 25 | } |
| 29 | 26 | ||
| 30 | /// Run the executor. | 27 | /// Single-threaded std-based executor. |
| 31 | /// | 28 | pub struct Executor { |
| 32 | /// The `init` closure is called with a [`Spawner`] that spawns tasks on | 29 | inner: raw::Executor, |
| 33 | /// this executor. Use it to spawn the initial task(s). After `init` returns, | 30 | not_send: PhantomData<*mut ()>, |
| 34 | /// the executor starts running the tasks. | 31 | signaler: &'static Signaler, |
| 35 | /// | 32 | } |
| 36 | /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), | ||
| 37 | /// for example by passing it as an argument to the initial tasks. | ||
| 38 | /// | ||
| 39 | /// This function requires `&'static mut self`. This means you have to store the | ||
| 40 | /// Executor instance in a place where it'll live forever and grants you mutable | ||
| 41 | /// access. There's a few ways to do this: | ||
| 42 | /// | ||
| 43 | /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) | ||
| 44 | /// - a `static mut` (unsafe) | ||
| 45 | /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) | ||
| 46 | /// | ||
| 47 | /// This function never returns. | ||
| 48 | pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | ||
| 49 | init(self.inner.spawner()); | ||
| 50 | 33 | ||
| 51 | loop { | 34 | impl Executor { |
| 52 | unsafe { self.inner.poll() }; | 35 | /// Create a new Executor. |
| 53 | self.signaler.wait() | 36 | pub fn new() -> Self { |
| 37 | let signaler = &*Box::leak(Box::new(Signaler::new())); | ||
| 38 | Self { | ||
| 39 | inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(signaler)))), | ||
| 40 | not_send: PhantomData, | ||
| 41 | signaler, | ||
| 42 | } | ||
| 54 | } | 43 | } |
| 55 | } | ||
| 56 | } | ||
| 57 | 44 | ||
| 58 | struct Signaler { | 45 | /// Run the executor. |
| 59 | mutex: Mutex<bool>, | 46 | /// |
| 60 | condvar: Condvar, | 47 | /// The `init` closure is called with a [`Spawner`] that spawns tasks on |
| 61 | } | 48 | /// this executor. Use it to spawn the initial task(s). After `init` returns, |
| 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()); | ||
| 62 | 65 | ||
| 63 | impl Signaler { | 66 | loop { |
| 64 | fn new() -> Self { | 67 | unsafe { self.inner.poll() }; |
| 65 | Self { | 68 | self.signaler.wait() |
| 66 | mutex: Mutex::new(false), | 69 | } |
| 67 | condvar: Condvar::new(), | ||
| 68 | } | 70 | } |
| 69 | } | 71 | } |
| 70 | 72 | ||
| 71 | fn wait(&self) { | 73 | struct Signaler { |
| 72 | let mut signaled = self.mutex.lock().unwrap(); | 74 | mutex: Mutex<bool>, |
| 73 | while !*signaled { | 75 | condvar: Condvar, |
| 74 | signaled = self.condvar.wait(signaled).unwrap(); | ||
| 75 | } | ||
| 76 | *signaled = false; | ||
| 77 | } | 76 | } |
| 78 | 77 | ||
| 79 | fn signal(&self) { | 78 | impl Signaler { |
| 80 | let mut signaled = self.mutex.lock().unwrap(); | 79 | fn new() -> Self { |
| 81 | *signaled = true; | 80 | Self { |
| 82 | self.condvar.notify_one(); | 81 | mutex: Mutex::new(false), |
| 82 | condvar: Condvar::new(), | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | fn wait(&self) { | ||
| 87 | let mut signaled = self.mutex.lock().unwrap(); | ||
| 88 | while !*signaled { | ||
| 89 | signaled = self.condvar.wait(signaled).unwrap(); | ||
| 90 | } | ||
| 91 | *signaled = false; | ||
| 92 | } | ||
| 93 | |||
| 94 | fn signal(&self) { | ||
| 95 | let mut signaled = self.mutex.lock().unwrap(); | ||
| 96 | *signaled = true; | ||
| 97 | self.condvar.notify_one(); | ||
| 98 | } | ||
| 83 | } | 99 | } |
| 84 | } | 100 | } |
