aboutsummaryrefslogtreecommitdiff
path: root/macros/src
diff options
context:
space:
mode:
authorGravatar bors[bot] <26634292+bors[bot]@users.noreply.github.com> 2021-04-07 12:01:18 +0000
committerGravatar GitHub <noreply@github.com> 2021-04-07 12:01:18 +0000
commit6c8257bb73de0f68072467447692a1f7dff555f9 (patch)
tree815ee7267e0661532f9c3ad13021b5293efd994f /macros/src
parent3c86d713a6f8fdb052de80380a17468090e42624 (diff)
parentae691952c328757113047bf696e934316789b844 (diff)
downloadrtic-6c8257bb73de0f68072467447692a1f7dff555f9.tar.gz
rtic-6c8257bb73de0f68072467447692a1f7dff555f9.tar.zst
rtic-6c8257bb73de0f68072467447692a1f7dff555f9.zip
Merge #456
456: Cancel/reschedule support for monotonics r=AfoHT a=korken89 Design document: https://hackmd.io/lhUCzrKBS-66aadO4KsSzw?view Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
Diffstat (limited to 'macros/src')
-rw-r--r--macros/src/codegen/module.rs113
-rw-r--r--macros/src/codegen/pre_init.rs12
-rw-r--r--macros/src/codegen/timer_queue.rs22
-rw-r--r--macros/src/codegen/util.rs5
4 files changed, 129 insertions, 23 deletions
diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs
index 75435b54..e15aab1c 100644
--- a/macros/src/codegen/module.rs
+++ b/macros/src/codegen/module.rs
@@ -21,6 +21,33 @@ pub fn codegen(
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
+ let all_task_names: Vec<_> = app
+ .software_tasks
+ .iter()
+ .map(|(name, st)| {
+ if !st.is_extern {
+ let cfgs = &st.cfgs;
+ quote! {
+ #(#cfgs)*
+ #[allow(unused_imports)]
+ use #app_path::#name as #name;
+ }
+ } else {
+ quote!()
+ }
+ })
+ .chain(app.hardware_tasks.iter().map(|(name, ht)| {
+ if !ht.is_extern {
+ quote! {
+ #[allow(unused_imports)]
+ use #app_path::#name as #name;
+ }
+ } else {
+ quote!()
+ }
+ }))
+ .collect();
+
let mut lt = None;
match ctxt {
Context::Init => {
@@ -202,6 +229,9 @@ pub fn codegen(
// Spawn caller
items.push(quote!(
+
+ #(#all_task_names)*
+
#(#cfgs)*
/// Spawns the task directly
pub fn spawn(#(#args,)*) -> Result<(), #ty> {
@@ -247,6 +277,7 @@ pub fn codegen(
if monotonic.args.default {
items.push(quote!(pub use #m::spawn_after;));
items.push(quote!(pub use #m::spawn_at;));
+ items.push(quote!(pub use #m::SpawnHandle;));
}
let (enable_interrupt, pend) = if &*m_isr.to_string() == "SysTick" {
@@ -264,15 +295,68 @@ pub fn codegen(
};
let user_imports = &app.user_imports;
+ let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
items.push(quote!(
/// Holds methods related to this monotonic
pub mod #m {
+ // #(
+ // #[allow(unused_imports)]
+ // use #app_path::#all_task_names as #all_task_names;
+ // )*
+ use super::*;
+ #[allow(unused_imports)]
+ use #app_path::#tq_marker;
+ #[allow(unused_imports)]
+ use #app_path::#t;
#(
#[allow(unused_imports)]
#user_imports
)*
+ pub struct SpawnHandle {
+ #[doc(hidden)]
+ marker: u32,
+ }
+
+ impl SpawnHandle {
+ pub fn cancel(self) -> Result<#ty, ()> {
+ rtic::export::interrupt::free(|_| unsafe {
+ let tq = &mut *#app_path::#tq.as_mut_ptr();
+ if let Some((_task, index)) = tq.cancel_marker(self.marker) {
+ // Get the message
+ let msg = #app_path::#inputs.get_unchecked(usize::from(index)).as_ptr().read();
+ // Return the index to the free queue
+ #app_path::#fq.split().0.enqueue_unchecked(index);
+
+ Ok(msg)
+ } else {
+ Err(())
+ }
+ })
+ }
+
+ #[inline]
+ pub fn reschedule_after<D>(self, duration: D) -> Result<Self, ()>
+ where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
+ D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
+ {
+ self.reschedule_at(#app_path::#m::now() + duration)
+ }
+
+ pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result<Self, ()>
+ {
+ rtic::export::interrupt::free(|_| unsafe {
+ let marker = #tq_marker;
+ #tq_marker = #tq_marker.wrapping_add(1);
+
+ let tq = &mut *#app_path::#tq.as_mut_ptr();
+
+ tq.update_marker(self.marker, marker, instant, || #pend).map(|_| SpawnHandle { marker })
+ })
+ }
+ }
+
#(#cfgs)*
/// Spawns the task after a set duration relative to the current time
///
@@ -281,7 +365,7 @@ pub fn codegen(
pub fn spawn_after<D>(
duration: D
#(,#args)*
- ) -> Result<(), #ty>
+ ) -> Result<SpawnHandle, #ty>
where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
{
@@ -300,7 +384,7 @@ pub fn codegen(
pub fn spawn_at(
instant: rtic::time::Instant<#app_path::#mono_type>
#(,#args)*
- ) -> Result<(), #ty> {
+ ) -> Result<SpawnHandle, #ty> {
unsafe {
let input = #tupled;
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
@@ -314,15 +398,21 @@ pub fn codegen(
.as_mut_ptr()
.write(instant);
- let nr = rtic::export::NotReady {
- instant,
- index,
- task: #app_path::#t::#name,
- };
+ rtic::export::interrupt::free(|_| {
+ let marker = #tq_marker;
+ let nr = rtic::export::NotReady {
+ instant,
+ index,
+ task: #app_path::#t::#name,
+ marker,
+ };
+
+ #tq_marker = #tq_marker.wrapping_add(1);
+
+ let tq = unsafe { &mut *#app_path::#tq.as_mut_ptr() };
- rtic::export::interrupt::free(|_|
if let Some(mono) = #app_path::#m_ident.as_mut() {
- #app_path::#tq.enqueue_unchecked(
+ tq.enqueue_unchecked(
nr,
|| #enable_interrupt,
|| #pend,
@@ -331,9 +421,10 @@ pub fn codegen(
// We can only use the timer queue if `init` has returned, and it
// writes the `Some(monotonic)` we are accessing here.
core::hint::unreachable_unchecked()
- });
+ }
- Ok(())
+ Ok(SpawnHandle { marker })
+ })
} else {
Err(input)
}
diff --git a/macros/src/codegen/pre_init.rs b/macros/src/codegen/pre_init.rs
index d5105445..287f41a4 100644
--- a/macros/src/codegen/pre_init.rs
+++ b/macros/src/codegen/pre_init.rs
@@ -77,12 +77,16 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
);));
}
- // Initialize monotonic's interrupts
- for (_, monotonic) in app.monotonics.iter()
- //.map(|(ident, monotonic)| (ident, &monotonic.args.priority, &monotonic.args.binds))
- {
+ // Initialize monotonic's interrupts and timer queues
+ for (_, monotonic) in &app.monotonics {
let priority = &monotonic.args.priority;
let binds = &monotonic.args.binds;
+ let monotonic_name = monotonic.ident.to_string();
+ let tq = util::tq_ident(&monotonic_name);
+ let tq = util::mark_internal_ident(&tq);
+
+ // Initialize timer queues
+ stmts.push(quote!(#tq.as_mut_ptr().write(rtic::export::TimerQueue::new());));
// Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs
index 82d0ac98..0d2c51ea 100644
--- a/macros/src/codegen/timer_queue.rs
+++ b/macros/src/codegen/timer_queue.rs
@@ -9,6 +9,15 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let mut items = vec![];
if !app.monotonics.is_empty() {
+ // Generate the marker counter used to track for `cancel` and `reschedule`
+ let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
+ items.push(quote!(
+ // #[doc = #doc]
+ #[doc(hidden)]
+ #[allow(non_camel_case_types)]
+ static mut #tq_marker: u32 = 0;
+ ));
+
let t = util::schedule_t_ident();
// Enumeration of `schedule`-able tasks
@@ -32,7 +41,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
- enum #t {
+ pub enum #t {
#(#variants,)*
}
));
@@ -59,15 +68,12 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
.map(|(_name, task)| task.args.capacity)
.sum();
let n = util::capacity_typenum(cap, false);
- let tq_ty = quote!(rtic::export::TimerQueue<#mono_type, #t, #n>);
+ let tq_ty =
+ quote!(core::mem::MaybeUninit<rtic::export::TimerQueue<#mono_type, #t, #n>>);
items.push(quote!(
#[doc(hidden)]
- static mut #tq: #tq_ty = rtic::export::TimerQueue(
- rtic::export::BinaryHeap(
- rtic::export::iBinaryHeap::new()
- )
- );
+ static mut #tq: #tq_ty = core::mem::MaybeUninit::uninit();
));
let mono = util::monotonic_ident(&monotonic_name);
@@ -129,7 +135,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
while let Some((task, index)) = rtic::export::interrupt::free(|_|
if let Some(mono) = #app_path::#m_ident.as_mut() {
- #tq.dequeue(|| #disable_isr, mono)
+ (&mut *#tq.as_mut_ptr()).dequeue(|| #disable_isr, mono)
} else {
// We can only use the timer queue if `init` has returned, and it
// writes the `Some(monotonic)` we are accessing here.
diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs
index 6589f62d..9ccdbf78 100644
--- a/macros/src/codegen/util.rs
+++ b/macros/src/codegen/util.rs
@@ -89,6 +89,11 @@ pub fn interrupt_ident() -> Ident {
Ident::new("interrupt", span)
}
+pub fn timer_queue_marker_ident() -> Ident {
+ let span = Span::call_site();
+ Ident::new("TIMER_QUEUE_MARKER", span)
+}
+
/// Whether `name` is an exception with configurable priority
pub fn is_exception(name: &Ident) -> bool {
let s = name.to_string();