spawn POC works, likely unsound

This commit is contained in:
Per Lindgren 2020-10-05 21:57:44 +02:00
parent 4eb4c4e7b2
commit 6bd168d711
9 changed files with 201 additions and 9 deletions

33
examples/spawn.rs Normal file
View file

@ -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();
}
}

View file

@ -20,6 +20,7 @@ mod schedule_body;
mod software_tasks;
mod spawn;
mod spawn_body;
mod spawn_module;
mod timer_queue;
mod util;

View file

@ -35,7 +35,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
#[doc = #doc]
enum #t {
pub enum #t {
#(#variants,)*
}
));
@ -57,7 +57,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
);
items.push(quote!(
#[doc = #doc]
static mut #rq: #rq_ty = #rq_expr;
pub static mut #rq: #rq_ty = #rq_expr;
));
if let Some(ceiling) = channel.ceiling {

View file

@ -97,6 +97,7 @@ pub fn codegen(
Context::HardwareTask(name),
needs_lt,
app,
analysis,
extra,
));

View file

@ -62,7 +62,8 @@ pub fn codegen(
root_idle.push(locals);
}
root_idle.push(module::codegen(Context::Idle, needs_lt, app, extra));
root_idle.push(module::codegen(Context::Idle, needs_lt, app,analysis, extra));
let attrs = &idle.attrs;
let context = &idle.context;

View file

@ -125,7 +125,13 @@ pub fn codegen(
quote!(let late = crate::#name(#(#locals_new,)* #name::Context::new(core.into()));),
);
root_init.push(module::codegen(Context::Init, needs_lt, app, extra));
root_init.push(module::codegen(
Context::Init,
needs_lt,
app,
analysis,
extra,
));
(mod_app, root_init, user_init, user_init_imports, call_init)
} else {

View file

@ -2,9 +2,16 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use rtic_syntax::{ast::App, Context};
use crate::{check::Extra, codegen::util};
// use crate::{analyze::Analysis, check::Extra, codegen::spawn_module, codegen::util};
use crate::{analyze::Analysis, check::Extra, codegen::util};
pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> 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)]

View file

@ -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,
));
}

View file

@ -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(())
// }
)
}