From 6bd168d711cd6304af72a106bb98f0cbebff0742 Mon Sep 17 00:00:00 2001 From: Per Lindgren Date: Mon, 5 Oct 2020 21:57:44 +0200 Subject: [PATCH] spawn POC works, likely unsound --- examples/spawn.rs | 33 ++++++++++++ macros/src/codegen.rs | 1 + macros/src/codegen/dispatchers.rs | 4 +- macros/src/codegen/hardware_tasks.rs | 1 + macros/src/codegen/idle.rs | 3 +- macros/src/codegen/init.rs | 8 ++- macros/src/codegen/module.rs | 74 +++++++++++++++++++++++++- macros/src/codegen/software_tasks.rs | 7 +-- macros/src/codegen/spawn_module.rs | 79 ++++++++++++++++++++++++++++ 9 files changed, 201 insertions(+), 9 deletions(-) create mode 100644 examples/spawn.rs create mode 100644 macros/src/codegen/spawn_module.rs diff --git a/examples/spawn.rs b/examples/spawn.rs new file mode 100644 index 0000000000..3ea775940b --- /dev/null +++ b/examples/spawn.rs @@ -0,0 +1,33 @@ +//! examples/message.rs + +#![deny(unsafe_code)] +// #![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m_semihosting::{debug, hprintln}; +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + #[init(spawn = [foo])] + fn init(_c: init::Context) { + foo::spawn(1, 2).unwrap(); + } + + #[task()] + fn foo(_c: foo::Context, x: i32, y: u32) { + hprintln!("foo {}, {}", x, y).unwrap(); + if x == 2 { + debug::exit(debug::EXIT_SUCCESS); + } + foo::spawn(2, 3).unwrap(); + } + + // RTIC requires that unused interrupts are declared in an extern block when + // using software tasks; these free interrupts will be used to dispatch the + // software tasks. + extern "C" { + fn SSI0(); + } +} diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index f230d3956d..cc173830c9 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -20,6 +20,7 @@ mod schedule_body; mod software_tasks; mod spawn; mod spawn_body; +mod spawn_module; mod timer_queue; mod util; diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs index 300aa996e0..eac0371d3b 100644 --- a/macros/src/codegen/dispatchers.rs +++ b/macros/src/codegen/dispatchers.rs @@ -35,7 +35,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec Vec TokenStream2 { +pub fn codegen( + ctxt: Context, + resources_tick: bool, + app: &App, + analysis: &Analysis, + extra: &Extra, +) -> TokenStream2 { let mut items = vec![]; let mut fields = vec![]; let mut values = vec![]; @@ -318,6 +325,69 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> } )); + // not sure if this is the right way, maybe its backwards, + // that spawn_module should put in in root + + if let Context::SoftwareTask(..) = ctxt { + let spawnee = &app.software_tasks[name]; + let priority = spawnee.args.priority; + let t = util::spawn_t_ident(priority); + let cfgs = &spawnee.cfgs; + let (args, tupled, _untupled, ty) = util::regroup_inputs(&spawnee.inputs); + let args = &args; + let tupled = &tupled; + let fq = util::fq_ident(name); + let rq = util::rq_ident(priority); + let inputs = util::inputs_ident(name); + + eprintln!("app name: {}", app.name); + eprintln!("inputs {}", &inputs); + eprintln!("task name: {}", name); + eprintln!("fq {}", fq); + eprintln!("rq {}", rq); + let app_name = &app.name; + let app_path = quote! {crate::#app_name}; + + let device = extra.device; + let enum_ = util::interrupt_ident(); + let interrupt = &analysis.interrupts.get(&priority); + let pend = { + quote!( + rtic::pend(#device::#enum_::#interrupt); + ) + }; + + eprintln!("pend {}", &pend); + + items.push(quote!( + #(#cfgs)* + pub fn spawn(#(#args,)*) -> Result<(), #ty> { + // #let_instant // do we need it? + use rtic::Mutex as _; + + let input = #tupled; + // TODO: use critical section, now we are unsafe + unsafe { + if let Some(index) = #app_path::#fq.dequeue() { + #app_path::#inputs + .get_unchecked_mut(usize::from(index)) + .as_mut_ptr() + .write(input); + + // #write_instant, do we need? + + #app_path::#rq.enqueue_unchecked((#app_path::#t::#name, index)); + + #pend + + Ok(()) + } else { + Err(input) + } + } + })); + } + if !items.is_empty() { quote!( #[allow(non_snake_case)] diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs index 4ae37e4e9b..b240d7aa70 100644 --- a/macros/src/codegen/software_tasks.rs +++ b/macros/src/codegen/software_tasks.rs @@ -54,7 +54,7 @@ pub fn codegen( mod_app.push(quote!( /// Queue version of a free-list that keeps track of empty slots in /// the following buffers - static mut #fq: #fq_ty = #fq_expr; + pub static mut #fq: #fq_ty = #fq_expr; )); // Generate a resource proxy if needed @@ -88,7 +88,7 @@ pub fn codegen( mod_app.push(quote!( #uninit /// Buffer that holds the instants associated to the inputs of a task - static mut #instants: + pub static mut #instants: [core::mem::MaybeUninit<<#m as rtic::Monotonic>::Instant>; #cap_lit] = [#(#elems,)*]; )); @@ -99,7 +99,7 @@ pub fn codegen( mod_app.push(quote!( #uninit /// Buffer that holds the inputs of a task - static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] = + pub static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] = [#(#elems,)*]; )); } @@ -161,6 +161,7 @@ pub fn codegen( Context::SoftwareTask(name), needs_lt, app, + analysis, extra, )); } diff --git a/macros/src/codegen/spawn_module.rs b/macros/src/codegen/spawn_module.rs new file mode 100644 index 0000000000..5d3f465257 --- /dev/null +++ b/macros/src/codegen/spawn_module.rs @@ -0,0 +1,79 @@ +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use rtic_syntax::{ast::App, Context}; +use syn::Ident; + +#[allow(unused_imports)] +use crate::{analyze::Analysis, check::Extra, codegen::util}; + +#[allow(dead_code)] +pub fn codegen( + _spawner: Context, + _name: &Ident, + _app: &App, + _analysis: &Analysis, + _extra: &Extra, +) -> TokenStream2 { + // let spawnee = &app.software_tasks[name]; + // let priority = spawnee.args.priority; + + // let write_instant = if app.uses_schedule() { + // let instants = util::instants_ident(name); + + // Some(quote!( + // #instants.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(instant); + // )) + // } else { + // None + // }; + + // let t = util::spawn_t_ident(priority); + // let fq = util::fq_ident(name); + // let rq = util::rq_ident(priority); + // let (dequeue, enqueue) = if spawner.is_init() { + // ( + // quote!(#fq.dequeue()), + // quote!(#rq.enqueue_unchecked((#t::#name, index));), + // ) + // } else { + // ( + // quote!((#fq { priority }.lock(|fq| fq.split().1.dequeue()))), + // quote!((#rq { priority }.lock(|rq| { + // rq.split().0.enqueue_unchecked((#t::#name, index)) + // }));), + // ) + // }; + + // let device = extra.device; + // let enum_ = util::interrupt_ident(); + // let interrupt = &analysis.interrupts.get(&priority); + // let pend = { + // quote!( + // rtic::pend(#device::#enum_::#interrupt); + // ) + // }; + + // let (_, tupled, _, _) = util::regroup_inputs(&spawnee.inputs); + // let inputs = util::inputs_ident(name); + quote!( + // unsafe { + // use rtic::Mutex as _; + + // let input = #tupled; + // // // if let Some(index) = #dequeue { + // // // #inputs.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(input); + + // // // #write_instant + + // // // #enqueue + + // // // #pend + + // // // Ok(()) + // // // } else { + // // // Err(input) + // // // } + // Ok(()) + // } + ) +}