aboutsummaryrefslogtreecommitdiff
path: root/macros/src/codegen
diff options
context:
space:
mode:
authorGravatar Emil Fresk <emil.fresk@gmail.com> 2022-06-10 20:08:46 +0200
committerGravatar Emil Fresk <emil.fresk@gmail.com> 2022-08-03 11:30:32 +0200
commitb2ec1fa65118813b400cf806e3ff492ea41f49ca (patch)
treea9e9e71a7f696ad2832392054af12cc0019756d7 /macros/src/codegen
parent13ccd92e630e2d2a477b5062a995a0fb1a2b7a28 (diff)
downloadrtic-b2ec1fa65118813b400cf806e3ff492ea41f49ca.tar.gz
rtic-b2ec1fa65118813b400cf806e3ff492ea41f49ca.tar.zst
rtic-b2ec1fa65118813b400cf806e3ff492ea41f49ca.zip
Example running, timeout and delay futures available
Diffstat (limited to 'macros/src/codegen')
-rw-r--r--macros/src/codegen/dispatchers.rs128
-rw-r--r--macros/src/codegen/module.rs34
-rw-r--r--macros/src/codegen/monotonic.rs251
-rw-r--r--macros/src/codegen/software_tasks.rs30
-rw-r--r--macros/src/codegen/timer_queue.rs36
-rw-r--r--macros/src/codegen/util.rs9
6 files changed, 434 insertions, 54 deletions
diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs
index a90a97c7..e6caa781 100644
--- a/macros/src/codegen/dispatchers.rs
+++ b/macros/src/codegen/dispatchers.rs
@@ -5,7 +5,7 @@ use rtic_syntax::ast::App;
use crate::{analyze::Analysis, check::Extra, codegen::util};
/// Generates task dispatchers
-pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
+pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![];
let interrupts = &analysis.interrupts;
@@ -64,6 +64,9 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
static #rq: rtic::RacyCell<#rq_ty> = rtic::RacyCell::new(#rq_expr);
));
+ let device = &extra.device;
+ let enum_ = util::interrupt_ident();
+ let interrupt = util::suffixed(&interrupts[&level].0.to_string());
let arms = channel
.tasks
.iter()
@@ -73,37 +76,124 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let fq = util::fq_ident(name);
let inputs = util::inputs_ident(name);
let (_, tupled, pats, _) = util::regroup_inputs(&task.inputs);
+ let exec_name = util::internal_task_ident(name, "EXEC");
- quote!(
- #(#cfgs)*
- #t::#name => {
- let #tupled =
- (&*#inputs
- .get())
- .get_unchecked(usize::from(index))
- .as_ptr()
- .read();
- (&mut *#fq.get_mut()).split().0.enqueue_unchecked(index);
- let priority = &rtic::export::Priority::new(PRIORITY);
- #name(
- #name::Context::new(priority)
- #(,#pats)*
- )
- }
- )
+ if task.is_async {
+ let executor_run_ident = util::executor_run_ident(name);
+
+ quote!(
+ #(#cfgs)*
+ #t::#name => {
+ if !(&mut *#exec_name.get_mut()).is_running() {
+ let #tupled =
+ (&*#inputs
+ .get())
+ .get_unchecked(usize::from(index))
+ .as_ptr()
+ .read();
+ (&mut *#fq.get_mut()).split().0.enqueue_unchecked(index);
+
+ let priority = &rtic::export::Priority::new(PRIORITY);
+ (&mut *#exec_name.get_mut()).spawn(#name(#name::Context::new(priority), #(,#pats)*));
+ #executor_run_ident.store(true, core::sync::atomic::Ordering::Relaxed);
+ } else {
+ retry_queue.push_unchecked((#t::#name, index));
+ }
+ }
+ )
+ } else {
+ quote!(
+ #(#cfgs)*
+ #t::#name => {
+ let #tupled =
+ (&*#inputs
+ .get())
+ .get_unchecked(usize::from(index))
+ .as_ptr()
+ .read();
+ (&mut *#fq.get_mut()).split().0.enqueue_unchecked(index);
+ let priority = &rtic::export::Priority::new(PRIORITY);
+ #name(
+ #name::Context::new(priority)
+ #(,#pats)*
+ )
+ }
+ )
+ }
})
.collect::<Vec<_>>();
+ for (name, task) in app.software_tasks.iter() {
+ if task.is_async {
+ let type_name = util::internal_task_ident(name, "F");
+ let exec_name = util::internal_task_ident(name, "EXEC");
+
+ stmts.push(quote!(
+ type #type_name = impl core::future::Future + 'static;
+ static #exec_name:
+ rtic::RacyCell<rtic::export::executor::AsyncTaskExecutor<#type_name>> =
+ rtic::RacyCell::new(rtic::export::executor::AsyncTaskExecutor::new());
+ ));
+ }
+ }
+
+ let n_executors: usize = app
+ .software_tasks
+ .iter()
+ .map(|(_, task)| if task.is_async { 1 } else { 0 })
+ .sum();
+
+ // TODO: This `retry_queue` comes from the current design of the dispatcher queue handling.
+ // To remove this we would need to redesign how the dispatcher handles queues, and this can
+ // be done as an optimization later.
+ //
+ // The core issue is that we should only dequeue the ready queue if the exexutor associated
+ // to the task is not running. As it is today this queue is blindly dequeued, see the
+ // `while let Some(...) = (&mut *#rq.get_mut())...` a few lines down. The current "hack" is
+ // to just requeue the executor run if it should not have been dequeued. This needs however
+ // to be done after the ready queue has been exhausted.
+ if n_executors > 0 {
+ stmts.push(quote!(
+ let mut retry_queue: rtic::export::Vec<_, #n_executors> = rtic::export::Vec::new();
+ ));
+ }
+
stmts.push(quote!(
while let Some((task, index)) = (&mut *#rq.get_mut()).split().1.dequeue() {
match task {
#(#arms)*
}
}
+
+ while let Some((task, index)) = retry_queue.pop() {
+ rtic::export::interrupt::free(|_| {
+ (&mut *#rq.get_mut()).enqueue_unchecked((task, index));
+ });
+ }
));
+ for (name, _task) in app.software_tasks.iter().filter_map(|(name, task)| {
+ if task.is_async {
+ Some((name, task))
+ } else {
+ None
+ }
+ }) {
+ let exec_name = util::internal_task_ident(name, "EXEC");
+
+ let executor_run_ident = util::executor_run_ident(name);
+ stmts.push(quote!(
+ if #executor_run_ident.load(core::sync::atomic::Ordering::Relaxed) {
+ #executor_run_ident.store(false, core::sync::atomic::Ordering::Relaxed);
+ (&mut *#exec_name.get_mut()).poll(|| {
+ #executor_run_ident.store(true, core::sync::atomic::Ordering::Release);
+ rtic::pend(#device::#enum_::#interrupt);
+ });
+ }
+ ));
+ }
+
let doc = format!("Interrupt handler to dispatch tasks at priority {}", level);
- let interrupt = util::suffixed(&interrupts[&level].0.to_string());
let attribute = &interrupts[&level].1.attrs;
items.push(quote!(
#[allow(non_snake_case)]
diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs
index fd8137fa..29f27662 100644
--- a/macros/src/codegen/module.rs
+++ b/macros/src/codegen/module.rs
@@ -54,14 +54,6 @@ pub fn codegen(
Context::Idle | Context::HardwareTask(_) | Context::SoftwareTask(_) => {}
}
- // if ctxt.has_locals(app) {
- // let ident = util::locals_ident(ctxt, app);
- // module_items.push(quote!(
- // #[doc(inline)]
- // pub use super::#ident as Locals;
- // ));
- // }
-
if ctxt.has_local_resources(app) {
let ident = util::local_resources_ident(ctxt, app);
let lt = if local_resources_tick {
@@ -133,6 +125,7 @@ pub fn codegen(
));
module_items.push(quote!(
+ #[doc(inline)]
pub use super::#internal_monotonics_ident as Monotonics;
));
}
@@ -193,6 +186,7 @@ pub fn codegen(
module_items.push(quote!(
#(#cfgs)*
+ #[doc(inline)]
pub use super::#internal_context_name as Context;
));
@@ -225,6 +219,8 @@ pub fn codegen(
#(#cfgs)*
/// Spawns the task directly
+ #[allow(non_snake_case)]
+ #[doc(hidden)]
pub fn #internal_spawn_ident(#(#args,)*) -> Result<(), #ty> {
let input = #tupled;
@@ -239,7 +235,6 @@ pub fn codegen(
rtic::export::interrupt::free(|_| {
(&mut *#rq.get_mut()).enqueue_unchecked((#t::#name, index));
});
-
rtic::pend(#device::#enum_::#interrupt);
Ok(())
@@ -252,6 +247,7 @@ pub fn codegen(
module_items.push(quote!(
#(#cfgs)*
+ #[doc(inline)]
pub use super::#internal_spawn_ident as spawn;
));
@@ -294,15 +290,21 @@ pub fn codegen(
if monotonic.args.default {
module_items.push(quote!(
+ #[doc(inline)]
pub use #m::spawn_after;
+ #[doc(inline)]
pub use #m::spawn_at;
+ #[doc(inline)]
pub use #m::SpawnHandle;
));
}
module_items.push(quote!(
pub mod #m {
+ #[doc(inline)]
pub use super::super::#internal_spawn_after_ident as spawn_after;
+ #[doc(inline)]
pub use super::super::#internal_spawn_at_ident as spawn_at;
+ #[doc(inline)]
pub use super::super::#internal_spawn_handle_ident as SpawnHandle;
}
));
@@ -316,6 +318,7 @@ pub fn codegen(
marker: u32,
}
+ #(#cfgs)*
impl core::fmt::Debug for #internal_spawn_handle_ident {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct(#spawn_handle_string).finish()
@@ -327,7 +330,7 @@ pub fn codegen(
pub fn cancel(self) -> Result<#ty, ()> {
rtic::export::interrupt::free(|_| unsafe {
let tq = &mut *#tq.get_mut();
- if let Some((_task, index)) = tq.cancel_marker(self.marker) {
+ if let Some((_task, index)) = tq.cancel_task_marker(self.marker) {
// Get the message
let msg = (&*#inputs
.get())
@@ -362,11 +365,12 @@ pub fn codegen(
let tq = (&mut *#tq.get_mut());
- tq.update_marker(self.marker, marker, instant, || #pend).map(|_| #name::#m::SpawnHandle { marker })
+ tq.update_task_marker(self.marker, marker, instant, || #pend).map(|_| #name::#m::SpawnHandle { marker })
})
}
}
+
#(#cfgs)*
/// Spawns the task after a set duration relative to the current time
///
@@ -407,10 +411,10 @@ pub fn codegen(
rtic::export::interrupt::free(|_| {
let marker = #tq_marker.get().read();
- let nr = rtic::export::NotReady {
- instant,
- index,
+ let nr = rtic::export::TaskNotReady {
task: #t::#name,
+ index,
+ instant,
marker,
};
@@ -418,7 +422,7 @@ pub fn codegen(
let tq = &mut *#tq.get_mut();
- tq.enqueue_unchecked(
+ tq.enqueue_task_unchecked(
nr,
|| #enable_interrupt,
|| #pend,
diff --git a/macros/src/codegen/monotonic.rs b/macros/src/codegen/monotonic.rs
new file mode 100644
index 00000000..685502ed
--- /dev/null
+++ b/macros/src/codegen/monotonic.rs
@@ -0,0 +1,251 @@
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+use rtic_syntax::ast::App;
+
+use crate::{analyze::Analysis, check::Extra, codegen::util};
+
+/// Generates monotonic module dispatchers
+pub fn codegen(app: &App, _analysis: &Analysis, _extra: &Extra) -> TokenStream2 {
+ let mut monotonic_parts: Vec<_> = Vec::new();
+
+ let tq_marker = util::timer_queue_marker_ident();
+
+ for (_, monotonic) in &app.monotonics {
+ // let instants = util::monotonic_instants_ident(name, &monotonic.ident);
+ let monotonic_name = monotonic.ident.to_string();
+
+ let tq = util::tq_ident(&monotonic_name);
+ let m = &monotonic.ident;
+ let m_ident = util::monotonic_ident(&monotonic_name);
+ let m_isr = &monotonic.args.binds;
+ let enum_ = util::interrupt_ident();
+ let name_str = &m.to_string();
+ let ident = util::monotonic_ident(name_str);
+ let doc = &format!(
+ "This module holds the static implementation for `{}::now()`",
+ name_str
+ );
+
+ let (enable_interrupt, pend) = if &*m_isr.to_string() == "SysTick" {
+ (
+ quote!(core::mem::transmute::<_, rtic::export::SYST>(()).enable_interrupt()),
+ quote!(rtic::export::SCB::set_pendst()),
+ )
+ } else {
+ let rt_err = util::rt_err_ident();
+ (
+ quote!(rtic::export::NVIC::unmask(#rt_err::#enum_::#m_isr)),
+ quote!(rtic::pend(#rt_err::#enum_::#m_isr)),
+ )
+ };
+
+ let default_monotonic = if monotonic.args.default {
+ quote!(
+ #[doc(inline)]
+ pub use #m::now;
+ #[doc(inline)]
+ pub use #m::delay;
+ #[doc(inline)]
+ pub use #m::timeout_at;
+ #[doc(inline)]
+ pub use #m::timeout_after;
+ )
+ } else {
+ quote!()
+ };
+
+ monotonic_parts.push(quote! {
+ #default_monotonic
+
+ #[doc = #doc]
+ #[allow(non_snake_case)]
+ pub mod #m {
+
+ /// Read the current time from this monotonic
+ pub fn now() -> <super::super::#m as rtic::Monotonic>::Instant {
+ rtic::export::interrupt::free(|_| {
+ use rtic::Monotonic as _;
+ if let Some(m) = unsafe{ &mut *super::super::#ident.get_mut() } {
+ m.now()
+ } else {
+ <super::super::#m as rtic::Monotonic>::zero()
+ }
+ })
+ }
+
+ fn enqueue_waker(
+ instant: <super::super::#m as rtic::Monotonic>::Instant,
+ waker: core::task::Waker
+ ) -> Result<u32, ()> {
+ unsafe {
+ rtic::export::interrupt::free(|_| {
+ let marker = super::super::#tq_marker.get().read();
+ super::super::#tq_marker.get_mut().write(marker.wrapping_add(1));
+
+ let nr = rtic::export::WakerNotReady {
+ waker,
+ instant,
+ marker,
+ };
+
+ let tq = &mut *super::super::#tq.get_mut();
+
+ tq.enqueue_waker(
+ nr,
+ || #enable_interrupt,
+ || #pend,
+ (&mut *super::super::#m_ident.get_mut()).as_mut()).map(|_| marker)
+ })
+ }
+ }
+
+ /// Delay
+ #[inline(always)]
+ #[allow(non_snake_case)]
+ pub fn delay(duration: <super::super::#m as rtic::Monotonic>::Duration)
+ -> DelayFuture {
+ let until = now() + duration;
+ DelayFuture { until, tq_marker: None }
+ }
+
+ /// Delay future.
+ #[allow(non_snake_case)]
+ #[allow(non_camel_case_types)]
+ pub struct DelayFuture {
+ until: <super::super::#m as rtic::Monotonic>::Instant,
+ tq_marker: Option<u32>,
+ }
+
+ impl core::future::Future for DelayFuture {
+ type Output = Result<(), ()>;
+
+ fn poll(
+ mut self: core::pin::Pin<&mut Self>,
+ cx: &mut core::task::Context<'_>
+ ) -> core::task::Poll<Self::Output> {
+ let mut s = self.as_mut();
+ let now = now();
+
+ if now >= s.until {
+ core::task::Poll::Ready(Ok(()))
+ } else {
+ if s.tq_marker.is_some() {
+ core::task::Poll::Pending
+ } else {
+ match enqueue_waker(s.until, cx.waker().clone()) {
+ Ok(marker) => {
+ s.tq_marker = Some(marker);
+ core::task::Poll::Pending
+ },
+ Err(()) => core::task::Poll::Ready(Err(())),
+ }
+ }
+ }
+ }
+ }
+
+ /// Timeout future.
+ #[allow(non_snake_case)]
+ #[allow(non_camel_case_types)]
+ pub struct TimeoutFuture<F: core::future::Future> {
+ future: F,
+ until: <super::super::#m as rtic::Monotonic>::Instant,
+ tq_marker: Option<u32>,
+ }
+
+ /// Timeout after
+ #[allow(non_snake_case)]
+ #[inline(always)]
+ pub fn timeout_after<F: core::future::Future>(
+ future: F,
+ duration: <super::super::#m as rtic::Monotonic>::Duration
+ ) -> TimeoutFuture<F> {
+ let until = now() + duration;
+ TimeoutFuture {
+ future,
+ until,
+ tq_marker: None,
+ }
+ }
+
+ /// Timeout at
+ #[allow(non_snake_case)]
+ #[inline(always)]
+ pub fn timeout_at<F: core::future::Future>(
+ future: F,
+ instant: <super::super::#m as rtic::Monotonic>::Instant
+ ) -> TimeoutFuture<F> {
+ TimeoutFuture {
+ future,
+ until: instant,
+ tq_marker: None,
+ }
+ }
+
+ impl<F> core::future::Future for TimeoutFuture<F>
+ where
+ F: core::future::Future,
+ {
+ type Output = Result<Result<F::Output, super::TimeoutError>, ()>;
+
+ fn poll(
+ self: core::pin::Pin<&mut Self>,
+ cx: &mut core::task::Context<'_>
+ ) -> core::task::Poll<Self::Output> {
+ let now = now();
+
+ // SAFETY: We don't move the underlying pinned value.
+ let mut s = unsafe { self.get_unchecked_mut() };
+ let future = unsafe { core::pin::Pin::new_unchecked(&mut s.future) };
+
+ match future.poll(cx) {
+ core::task::Poll::Ready(r) => {
+ if let Some(marker) = s.tq_marker {
+ rtic::export::interrupt::free(|_| unsafe {
+ let tq = &mut *super::super::#tq.get_mut();
+ tq.cancel_waker_marker(marker);
+ });
+ }
+
+ core::task::Poll::Ready(Ok(Ok(r)))
+ }
+ core::task::Poll::Pending => {
+ if now >= s.until {
+ // Timeout
+ core::task::Poll::Ready(Ok(Err(super::TimeoutError)))
+ } else if s.tq_marker.is_none() {
+ match enqueue_waker(s.until, cx.waker().clone()) {
+ Ok(marker) => {
+ s.tq_marker = Some(marker);
+ core::task::Poll::Pending
+ },
+ Err(()) => core::task::Poll::Ready(Err(())), // TQ full
+ }
+ } else {
+ core::task::Poll::Pending
+ }
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+
+ if monotonic_parts.is_empty() {
+ quote!()
+ } else {
+ quote!(
+ pub use rtic::Monotonic as _;
+
+ /// Holds static methods for each monotonic.
+ pub mod monotonics {
+ /// A timeout error.
+ #[derive(Debug)]
+ pub struct TimeoutError;
+
+ #(#monotonic_parts)*
+ }
+ )
+ }
+}
diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs
index 78f6c961..6d08a221 100644
--- a/macros/src/codegen/software_tasks.rs
+++ b/macros/src/codegen/software_tasks.rs
@@ -27,13 +27,8 @@ pub fn codegen(
let mut root = vec![];
let mut user_tasks = vec![];
- // Async tasks
- for (name, task) in app.software_tasks.iter().filter(|(_, task)| task.is_async) {
- // todo
- }
-
- // Non-async tasks
- for (name, task) in app.software_tasks.iter().filter(|(_, task)| !task.is_async) {
+ // Any task
+ for (name, task) in app.software_tasks.iter() {
let inputs = &task.inputs;
let (_, _, _, input_ty) = util::regroup_inputs(inputs);
@@ -87,6 +82,7 @@ pub fn codegen(
let uninit = mk_uninit();
let inputs_ident = util::inputs_ident(name);
+
mod_app.push(quote!(
#uninit
// /// Buffer that holds the inputs of a task
@@ -96,6 +92,18 @@ pub fn codegen(
static #inputs_ident: rtic::RacyCell<[core::mem::MaybeUninit<#input_ty>; #cap_lit]> =
rtic::RacyCell::new([#(#elems,)*]);
));
+ if task.is_async {
+ let executor_ident = util::executor_run_ident(name);
+ mod_app.push(quote!(
+ #[allow(non_camel_case_types)]
+ #[allow(non_upper_case_globals)]
+ #[doc(hidden)]
+ static #executor_ident: core::sync::atomic::AtomicBool =
+ core::sync::atomic::AtomicBool::new(false);
+ ));
+ }
+
+ let inputs = &task.inputs;
// `${task}Resources`
let mut shared_needs_lt = false;
@@ -131,11 +139,17 @@ pub fn codegen(
let attrs = &task.attrs;
let cfgs = &task.cfgs;
let stmts = &task.stmts;
+ let async_marker = if task.is_async {
+ quote!(async)
+ } else {
+ quote!()
+ };
+
user_tasks.push(quote!(
#(#attrs)*
#(#cfgs)*
#[allow(non_snake_case)]
- fn #name(#context: #name::Context #(,#inputs)*) {
+ #async_marker fn #name(#context: #name::Context #(,#inputs)*) {
use rtic::Mutex as _;
use rtic::mutex::prelude::*;
diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs
index 32e288c5..513f78af 100644
--- a/macros/src/codegen/timer_queue.rs
+++ b/macros/src/codegen/timer_queue.rs
@@ -1,9 +1,8 @@
+use crate::{analyze::Analysis, check::Extra, codegen::util};
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use rtic_syntax::ast::App;
-use crate::{analyze::Analysis, check::Extra, codegen::util};
-
/// Generates timer queues and timer queue handlers
#[allow(clippy::too_many_lines)]
pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
@@ -67,8 +66,14 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
.iter()
.map(|(_name, task)| task.args.capacity as usize)
.sum();
- let n = util::capacity_literal(cap);
- let tq_ty = quote!(rtic::export::TimerQueue<#mono_type, #t, #n>);
+ let n_task = util::capacity_literal(cap);
+ let n_worker: usize = app
+ .software_tasks
+ .iter()
+ .map(|(_name, task)| task.is_async as usize)
+ .sum();
+ let n_worker = util::capacity_literal(n_worker);
+ let tq_ty = quote!(rtic::export::TimerQueue<#mono_type, #t, #n_task, #n_worker>);
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
@@ -76,8 +81,12 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
- static #tq: rtic::RacyCell<#tq_ty> =
- rtic::RacyCell::new(rtic::export::TimerQueue(rtic::export::SortedLinkedList::new_u16()));
+ static #tq: rtic::RacyCell<#tq_ty> = rtic::RacyCell::new(
+ rtic::export::TimerQueue {
+ task_queue: rtic::export::SortedLinkedList::new_u16(),
+ waker_queue: rtic::export::SortedLinkedList::new_u16(),
+ }
+ );
));
let mono = util::monotonic_ident(&monotonic_name);
@@ -118,7 +127,9 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
quote!(
#(#cfgs)*
#t::#name => {
- rtic::export::interrupt::free(|_| (&mut *#rq.get_mut()).split().0.enqueue_unchecked((#rqt::#name, index)));
+ rtic::export::interrupt::free(|_|
+ (&mut *#rq.get_mut()).split().0.enqueue_unchecked((#rqt::#name, index))
+ );
#pend
}
@@ -137,7 +148,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[no_mangle]
#[allow(non_snake_case)]
unsafe fn #bound_interrupt() {
- while let Some((task, index)) = rtic::export::interrupt::free(|_|
+ while let Some(task_or_waker) = rtic::export::interrupt::free(|_|
if let Some(mono) = (&mut *#m_ident.get_mut()).as_mut() {
(&mut *#tq.get_mut()).dequeue(|| #disable_isr, mono)
} else {
@@ -146,8 +157,13 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
core::hint::unreachable_unchecked()
})
{
- match task {
- #(#arms)*
+ match task_or_waker {
+ rtic::export::TaskOrWaker::Waker(waker) => waker.wake(),
+ rtic::export::TaskOrWaker::Task((task, index)) => {
+ match task {
+ #(#arms)*
+ }
+ }
}
}
diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs
index 0a3edc20..a0a59090 100644
--- a/macros/src/codegen/util.rs
+++ b/macros/src/codegen/util.rs
@@ -67,6 +67,11 @@ pub fn inputs_ident(task: &Ident) -> Ident {
mark_internal_name(&format!("{}_INPUTS", task))
}
+/// Generates an identifier for the `EXECUTOR_RUN` atomics (`async` API)
+pub fn executor_run_ident(task: &Ident) -> Ident {
+ mark_internal_name(&format!("{}_EXECUTOR_RUN", task))
+}
+
/// Generates an identifier for the `INSTANTS` buffer (`schedule` API)
pub fn monotonic_instants_ident(task: &Ident, monotonic: &Ident) -> Ident {
mark_internal_name(&format!("{}_{}_INSTANTS", task, monotonic))
@@ -222,7 +227,7 @@ pub fn rq_ident(priority: u8) -> Ident {
/// Generates an identifier for the `enum` of `schedule`-able tasks
pub fn schedule_t_ident() -> Ident {
- Ident::new("SCHED_T", Span::call_site())
+ mark_internal_name("SCHED_T")
}
/// Generates an identifier for the `enum` of `spawn`-able tasks
@@ -230,7 +235,7 @@ pub fn schedule_t_ident() -> Ident {
/// This identifier needs the same structure as the `RQ` identifier because there's one ready queue
/// for each of these `T` enums
pub fn spawn_t_ident(priority: u8) -> Ident {
- Ident::new(&format!("P{}_T", priority), Span::call_site())
+ mark_internal_name(&format!("P{}_T", priority))
}
/// Suffixed identifier