aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-executor-macros/src/lib.rs29
-rw-r--r--embassy-executor-macros/src/macros/main.rs29
-rw-r--r--embassy-executor/Cargo.toml2
-rw-r--r--embassy-executor/src/arch/spin.rs58
-rw-r--r--embassy-executor/src/lib.rs10
5 files changed, 126 insertions, 2 deletions
diff --git a/embassy-executor-macros/src/lib.rs b/embassy-executor-macros/src/lib.rs
index 5461fe04c..61d388b9e 100644
--- a/embassy-executor-macros/src/lib.rs
+++ b/embassy-executor-macros/src/lib.rs
@@ -94,6 +94,35 @@ pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
94 main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into() 94 main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into()
95} 95}
96 96
97/// Creates a new `executor` instance and declares an architecture agnostic application entry point spawning
98/// the corresponding function body as an async task.
99///
100/// The following restrictions apply:
101///
102/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks.
103/// * The function must be declared `async`.
104/// * The function must not use generics.
105/// * Only a single `main` task may be declared.
106///
107/// A user-defined entry macro must provided via the `entry` argument
108///
109/// ## Examples
110/// Spawning a task:
111/// ``` rust
112/// #[embassy_executor::main(entry = "qingke_rt::entry")]
113/// async fn main(_s: embassy_executor::Spawner) {
114/// // Function body
115/// }
116/// ```
117#[proc_macro_attribute]
118pub fn main_spin(args: TokenStream, item: TokenStream) -> TokenStream {
119 let args = syn::parse_macro_input!(args as Args);
120 let f = syn::parse_macro_input!(item as syn::ItemFn);
121 main::run(&args.meta, f, main::spin(&args.meta))
122 .unwrap_or_else(|x| x)
123 .into()
124}
125
97/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task. 126/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task.
98/// 127///
99/// The following restrictions apply: 128/// The following restrictions apply:
diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs
index 26dfa2397..66a3965d0 100644
--- a/embassy-executor-macros/src/macros/main.rs
+++ b/embassy-executor-macros/src/macros/main.rs
@@ -1,5 +1,5 @@
1use darling::export::NestedMeta; 1use darling::export::NestedMeta;
2use darling::FromMeta; 2use darling::{Error, FromMeta};
3use proc_macro2::TokenStream; 3use proc_macro2::TokenStream;
4use quote::quote; 4use quote::quote;
5use syn::{Expr, ReturnType, Type}; 5use syn::{Expr, ReturnType, Type};
@@ -50,6 +50,33 @@ pub fn riscv(args: &[NestedMeta]) -> TokenStream {
50 } 50 }
51} 51}
52 52
53pub fn spin(args: &[NestedMeta]) -> TokenStream {
54 let maybe_entry = match Args::from_list(args) {
55 Ok(args) => args.entry,
56 Err(e) => return e.write_errors(),
57 };
58
59 let entry = match maybe_entry {
60 Some(str) => str,
61 None => return Error::missing_field("entry").write_errors(),
62 };
63 let entry = match Expr::from_string(&entry) {
64 Ok(expr) => expr,
65 Err(e) => return e.write_errors(),
66 };
67
68 quote! {
69 #[#entry]
70 fn main() -> ! {
71 let mut executor = ::embassy_executor::Executor::new();
72 let executor = unsafe { __make_static(&mut executor) };
73 executor.run(|spawner| {
74 spawner.must_spawn(__embassy_main(spawner));
75 })
76 }
77 }
78}
79
53pub fn cortex_m() -> TokenStream { 80pub fn cortex_m() -> TokenStream {
54 quote! { 81 quote! {
55 #[cortex_m_rt::entry] 82 #[cortex_m_rt::entry]
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 01fa28b88..e2fedce3c 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -82,6 +82,8 @@ arch-riscv32 = ["_arch"]
82arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys", "critical-section/std"] 82arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys", "critical-section/std"]
83## AVR 83## AVR
84arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"] 84arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"]
85## spin (architecture agnostic; never sleeps)
86arch-spin = ["_arch"]
85 87
86#! ### Executor 88#! ### Executor
87 89
diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs
new file mode 100644
index 000000000..340023620
--- /dev/null
+++ b/embassy-executor/src/arch/spin.rs
@@ -0,0 +1,58 @@
1#[cfg(feature = "executor-interrupt")]
2compile_error!("`executor-interrupt` is not supported with `arch-spin`.");
3
4#[cfg(feature = "executor-thread")]
5pub use thread::*;
6#[cfg(feature = "executor-thread")]
7mod thread {
8 use core::marker::PhantomData;
9
10 pub use embassy_executor_macros::main_spin as main;
11
12 use crate::{raw, Spawner};
13
14 #[export_name = "__pender"]
15 fn __pender(_context: *mut ()) {}
16
17 /// Spin Executor
18 pub struct Executor {
19 inner: raw::Executor,
20 not_send: PhantomData<*mut ()>,
21 }
22
23 impl Executor {
24 /// Create a new Executor.
25 pub fn new() -> Self {
26 Self {
27 inner: raw::Executor::new(core::ptr::null_mut()),
28 not_send: PhantomData,
29 }
30 }
31
32 /// Run the executor.
33 ///
34 /// The `init` closure is called with a [`Spawner`] that spawns tasks on
35 /// this executor. Use it to spawn the initial task(s). After `init` returns,
36 /// the executor starts running the tasks.
37 ///
38 /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`),
39 /// for example by passing it as an argument to the initial tasks.
40 ///
41 /// This function requires `&'static mut self`. This means you have to store the
42 /// Executor instance in a place where it'll live forever and grants you mutable
43 /// access. There's a few ways to do this:
44 ///
45 /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
46 /// - a `static mut` (unsafe)
47 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
48 ///
49 /// This function never returns.
50 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
51 init(self.inner.spawner());
52
53 loop {
54 unsafe { self.inner.poll() };
55 }
56 }
57 }
58}
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index 6a2e493a2..d816539ac 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -23,7 +23,14 @@ macro_rules! check_at_most_one {
23 check_at_most_one!(@amo [$($f)*] [$($f)*] []); 23 check_at_most_one!(@amo [$($f)*] [$($f)*] []);
24 }; 24 };
25} 25}
26check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); 26check_at_most_one!(
27 "arch-avr",
28 "arch-cortex-m",
29 "arch-riscv32",
30 "arch-std",
31 "arch-wasm",
32 "arch-spin",
33);
27 34
28#[cfg(feature = "_arch")] 35#[cfg(feature = "_arch")]
29#[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")] 36#[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")]
@@ -31,6 +38,7 @@ check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arc
31#[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] 38#[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")]
32#[cfg_attr(feature = "arch-std", path = "arch/std.rs")] 39#[cfg_attr(feature = "arch-std", path = "arch/std.rs")]
33#[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")] 40#[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")]
41#[cfg_attr(feature = "arch-spin", path = "arch/spin.rs")]
34mod arch; 42mod arch;
35 43
36#[cfg(feature = "_arch")] 44#[cfg(feature = "_arch")]