mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-29 15:04:32 +01:00
spawn POC works, likely unsound
This commit is contained in:
parent
4eb4c4e7b2
commit
6bd168d711
9 changed files with 201 additions and 9 deletions
33
examples/spawn.rs
Normal file
33
examples/spawn.rs
Normal 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();
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ mod schedule_body;
|
|||
mod software_tasks;
|
||||
mod spawn;
|
||||
mod spawn_body;
|
||||
mod spawn_module;
|
||||
mod timer_queue;
|
||||
mod util;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -97,6 +97,7 @@ pub fn codegen(
|
|||
Context::HardwareTask(name),
|
||||
needs_lt,
|
||||
app,
|
||||
analysis,
|
||||
extra,
|
||||
));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
}
|
||||
|
|
79
macros/src/codegen/spawn_module.rs
Normal file
79
macros/src/codegen/spawn_module.rs
Normal 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(())
|
||||
// }
|
||||
)
|
||||
}
|
Loading…
Reference in a new issue