diff options
Diffstat (limited to 'embassy-executor/src/arch/wasm.rs')
| -rw-r--r-- | embassy-executor/src/arch/wasm.rs | 134 |
1 files changed, 74 insertions, 60 deletions
diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index 98091cfbb..08ab16b99 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs | |||
| @@ -1,74 +1,88 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | #[cfg(feature = "executor-interrupt")] |
| 2 | compile_error!("`executor-interrupt` is not supported with `arch-wasm`."); | ||
| 2 | 3 | ||
| 3 | use js_sys::Promise; | 4 | #[cfg(feature = "executor-thread")] |
| 4 | use wasm_bindgen::prelude::*; | 5 | pub use thread::*; |
| 6 | #[cfg(feature = "executor-thread")] | ||
| 7 | mod thread { | ||
| 5 | 8 | ||
| 6 | use super::raw::util::UninitCell; | 9 | use core::marker::PhantomData; |
| 7 | use super::raw::{self}; | ||
| 8 | use super::Spawner; | ||
| 9 | 10 | ||
| 10 | /// WASM executor, wasm_bindgen to schedule tasks on the JS event loop. | 11 | #[cfg(feature = "nightly")] |
| 11 | pub struct Executor { | 12 | pub use embassy_macros::main_wasm as main; |
| 12 | inner: raw::Executor, | 13 | use js_sys::Promise; |
| 13 | ctx: &'static WasmContext, | 14 | use wasm_bindgen::prelude::*; |
| 14 | not_send: PhantomData<*mut ()>, | ||
| 15 | } | ||
| 16 | 15 | ||
| 17 | pub(crate) struct WasmContext { | 16 | use crate::raw::util::UninitCell; |
| 18 | promise: Promise, | 17 | use crate::raw::{Pender, PenderInner}; |
| 19 | closure: UninitCell<Closure<dyn FnMut(JsValue)>>, | 18 | use crate::{raw, Spawner}; |
| 20 | } | 19 | |
| 20 | /// WASM executor, wasm_bindgen to schedule tasks on the JS event loop. | ||
| 21 | pub struct Executor { | ||
| 22 | inner: raw::Executor, | ||
| 23 | ctx: &'static WasmContext, | ||
| 24 | not_send: PhantomData<*mut ()>, | ||
| 25 | } | ||
| 26 | |||
| 27 | pub(crate) struct WasmContext { | ||
| 28 | promise: Promise, | ||
| 29 | closure: UninitCell<Closure<dyn FnMut(JsValue)>>, | ||
| 30 | } | ||
| 31 | |||
| 32 | #[derive(Copy, Clone)] | ||
| 33 | pub(crate) struct ThreadPender(&'static WasmContext); | ||
| 21 | 34 | ||
| 22 | impl WasmContext { | 35 | impl ThreadPender { |
| 23 | pub fn new() -> Self { | 36 | #[allow(unused)] |
| 24 | Self { | 37 | pub(crate) fn pend(self) { |
| 25 | promise: Promise::resolve(&JsValue::undefined()), | 38 | let _ = self.0.promise.then(unsafe { self.0.closure.as_mut() }); |
| 26 | closure: UninitCell::uninit(), | ||
| 27 | } | 39 | } |
| 28 | } | 40 | } |
| 29 | } | ||
| 30 | 41 | ||
| 31 | impl Executor { | 42 | impl WasmContext { |
| 32 | /// Create a new Executor. | 43 | pub fn new() -> Self { |
| 33 | pub fn new() -> Self { | 44 | Self { |
| 34 | let ctx = &*Box::leak(Box::new(WasmContext::new())); | 45 | promise: Promise::resolve(&JsValue::undefined()), |
| 35 | let inner = raw::Executor::new( | 46 | closure: UninitCell::uninit(), |
| 36 | |p| unsafe { | 47 | } |
| 37 | let ctx = &*(p as *const () as *const WasmContext); | ||
| 38 | let _ = ctx.promise.then(ctx.closure.as_mut()); | ||
| 39 | }, | ||
| 40 | ctx as *const _ as _, | ||
| 41 | ); | ||
| 42 | Self { | ||
| 43 | inner, | ||
| 44 | not_send: PhantomData, | ||
| 45 | ctx, | ||
| 46 | } | 48 | } |
| 47 | } | 49 | } |
| 48 | 50 | ||
| 49 | /// Run the executor. | 51 | impl Executor { |
| 50 | /// | 52 | /// Create a new Executor. |
| 51 | /// The `init` closure is called with a [`Spawner`] that spawns tasks on | 53 | pub fn new() -> Self { |
| 52 | /// this executor. Use it to spawn the initial task(s). After `init` returns, | 54 | let ctx = &*Box::leak(Box::new(WasmContext::new())); |
| 53 | /// the executor starts running the tasks. | 55 | Self { |
| 54 | /// | 56 | inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(ctx)))), |
| 55 | /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), | 57 | not_send: PhantomData, |
| 56 | /// for example by passing it as an argument to the initial tasks. | 58 | ctx, |
| 57 | /// | 59 | } |
| 58 | /// This function requires `&'static mut self`. This means you have to store the | 60 | } |
| 59 | /// Executor instance in a place where it'll live forever and grants you mutable | 61 | |
| 60 | /// access. There's a few ways to do this: | 62 | /// Run the executor. |
| 61 | /// | 63 | /// |
| 62 | /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) | 64 | /// The `init` closure is called with a [`Spawner`] that spawns tasks on |
| 63 | /// - a `static mut` (unsafe) | 65 | /// this executor. Use it to spawn the initial task(s). After `init` returns, |
| 64 | /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) | 66 | /// the executor starts running the tasks. |
| 65 | pub fn start(&'static mut self, init: impl FnOnce(Spawner)) { | 67 | /// |
| 66 | unsafe { | 68 | /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), |
| 67 | let executor = &self.inner; | 69 | /// for example by passing it as an argument to the initial tasks. |
| 68 | self.ctx.closure.write(Closure::new(move |_| { | 70 | /// |
| 69 | executor.poll(); | 71 | /// This function requires `&'static mut self`. This means you have to store the |
| 70 | })); | 72 | /// Executor instance in a place where it'll live forever and grants you mutable |
| 71 | init(self.inner.spawner()); | 73 | /// access. There's a few ways to do this: |
| 74 | /// | ||
| 75 | /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) | ||
| 76 | /// - a `static mut` (unsafe) | ||
| 77 | /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) | ||
| 78 | pub fn start(&'static mut self, init: impl FnOnce(Spawner)) { | ||
| 79 | unsafe { | ||
| 80 | let executor = &self.inner; | ||
| 81 | self.ctx.closure.write(Closure::new(move |_| { | ||
| 82 | executor.poll(); | ||
| 83 | })); | ||
| 84 | init(self.inner.spawner()); | ||
| 85 | } | ||
| 72 | } | 86 | } |
| 73 | } | 87 | } |
| 74 | } | 88 | } |
