diff options
author | 2021-04-07 12:01:18 +0000 | |
---|---|---|
committer | 2021-04-07 12:01:18 +0000 | |
commit | 6c8257bb73de0f68072467447692a1f7dff555f9 (patch) | |
tree | 815ee7267e0661532f9c3ad13021b5293efd994f /macros/src | |
parent | 3c86d713a6f8fdb052de80380a17468090e42624 (diff) | |
parent | ae691952c328757113047bf696e934316789b844 (diff) | |
download | rtic-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.rs | 113 | ||||
-rw-r--r-- | macros/src/codegen/pre_init.rs | 12 | ||||
-rw-r--r-- | macros/src/codegen/timer_queue.rs | 22 | ||||
-rw-r--r-- | macros/src/codegen/util.rs | 5 |
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(); |