task! is not needed if tasks.$T.path is specified

This commit is contained in:
Jorge Aparicio 2017-07-24 22:46:29 -05:00
parent 74daa77fe0
commit fb4542818b
3 changed files with 120 additions and 54 deletions

View file

@ -18,6 +18,7 @@ pub type Tasks = HashMap<Ident, Task>;
pub struct Task { pub struct Task {
pub enabled: Option<bool>, pub enabled: Option<bool>,
pub path: Option<Path>,
pub priority: u8, pub priority: u8,
pub resources: Idents, pub resources: Idents,
} }
@ -71,6 +72,7 @@ fn task(task: syntax::check::Task) -> Result<Task> {
if let Some(priority) = task.priority { if let Some(priority) = task.priority {
Ok(Task { Ok(Task {
enabled: task.enabled, enabled: task.enabled,
path: task.path,
priority, priority,
resources: task.resources, resources: task.resources,
}) })

View file

@ -1,4 +1,5 @@
use quote::{Ident, Tokens}; use quote::{Ident, Tokens};
use syn::{Lit, StrStyle};
use analyze::{Ownership, Ownerships}; use analyze::{Ownership, Ownerships};
use check::App; use check::App;
@ -497,89 +498,148 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
let mut lifetime = None; let mut lifetime = None;
let mut needs_reexport = false; let mut needs_reexport = false;
for name in &task.resources { let mut needs_threshold = false;
match ownerships[name] { let has_resources = !task.resources.is_empty();
Ownership::Shared { ceiling } if ceiling > task.priority => {
fields.push(quote! {
pub #name: super::_resource::#name,
});
exprs.push(quote! { if has_resources {
#name: { for name in &task.resources {
super::_resource::#name::new() match ownerships[name] {
}, Ownership::Shared { ceiling }
}); if ceiling > task.priority =>
} {
_ => { needs_threshold = true;
lifetime = Some(quote!('a));
if let Some(resource) = app.resources.get(name) {
needs_reexport = true;
let ty = &resource.ty;
fields.push(quote! { fields.push(quote! {
pub #name: &'a mut ::#krate::Static<#ty>, pub #name: super::_resource::#name,
}); });
exprs.push(quote! { exprs.push(quote! {
#name: ::#krate::Static::ref_mut(&mut super::#name), #name: {
super::_resource::#name::new()
},
}); });
} else { }
fields.push(quote! { _ => {
pub #name: lifetime = Some(quote!('a));
if let Some(resource) = app.resources.get(name) {
needs_reexport = true;
let ty = &resource.ty;
fields.push(quote! {
pub #name: &'a mut ::#krate::Static<#ty>,
});
exprs.push(quote! {
#name: ::#krate::Static::ref_mut(&mut super::#name),
});
} else {
fields.push(quote! {
pub #name:
&'a mut ::#krate::Static<::#device::#name>, &'a mut ::#krate::Static<::#device::#name>,
}); });
exprs.push(quote! { exprs.push(quote! {
#name: ::#krate::Static::ref_mut( #name: ::#krate::Static::ref_mut(
&mut *::#device::#name.get(), &mut *::#device::#name.get(),
), ),
}); });
}
} }
} }
} }
if needs_reexport {
let rname = Ident::new(format!("_{}Resources", name));
root.push(quote! {
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
pub struct #rname<#lifetime> {
#(#fields)*
}
});
items.push(quote! {
pub use ::#rname as Resources;
});
} else {
items.push(quote! {
#[allow(non_snake_case)]
pub struct Resources<#lifetime> {
#(#fields)*
}
});
}
items.push(quote! {
#[allow(unsafe_code)]
impl<#lifetime> Resources<#lifetime> {
pub unsafe fn new() -> Self {
Resources {
#(#exprs)*
}
}
}
});
} }
if needs_reexport { if let Some(path) = task.path.as_ref() {
let rname = Ident::new(format!("_{}Resources", name)); let mut tys = vec![];
let mut exprs = vec![];
let priority = task.priority;
if needs_threshold {
tys.push(quote!(&mut Threshold));
exprs.push(quote!(&mut Threshold::new(#priority)));
}
if has_resources {
tys.push(quote!(#name::Resources));
exprs.push(quote!(#name::Resources::new()));
}
let _name = Ident::new(format!("_{}", name));
let export_name = Lit::Str(name.as_ref().to_owned(), StrStyle::Cooked);
root.push(quote! { root.push(quote! {
#[allow(non_camel_case_types)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub struct #rname<#lifetime> { #[allow(unsafe_code)]
#(#fields)* #[export_name = #export_name]
pub unsafe extern "C" fn #_name() {
let f: fn(#(#tys,)*) = #path;
f(#(#exprs,)*)
} }
}); });
} else if !has_resources {
items.push(quote! { items.push(quote! {
pub use ::#rname as Resources; pub struct Resources {
}); _0: (),
} else {
items.push(quote! {
#[allow(non_snake_case)]
pub struct Resources<#lifetime> {
#(#fields)*
} }
});
}
items.push(quote! { impl Resources {
#[allow(unsafe_code)] pub unsafe fn new() -> Self {
impl<#lifetime> Resources<#lifetime> { Resources { _0: () }
pub unsafe fn new() -> Self {
Resources {
#(#exprs)*
} }
} }
} });
}); // the `task!` macro will be used so the `#NAME::Resources` type
// must exist
}
let priority = task.priority; let priority = task.priority;
if task.path.is_none() {
// This `const`ant is mainly used to make sure the user doesn't
// forget to set a task handler using the `task!` macro. They'll get
// an error if they do.
items.push(quote! {
#[deny(dead_code)]
pub const #name: u8 = #priority;
});
}
root.push(quote!{ root.push(quote!{
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[allow(unsafe_code)] #[allow(unsafe_code)]
mod #name { mod #name {
#[deny(dead_code)]
pub const #name: u8 = #priority;
#[allow(dead_code)] #[allow(dead_code)]
#[deny(const_err)] #[deny(const_err)]
const CHECK_PRIORITY: (u8, u8) = ( const CHECK_PRIORITY: (u8, u8) = (

View file

@ -191,6 +191,10 @@ impl Threshold {
impl !Send for Threshold {} impl !Send for Threshold {}
/// Sets an interrupt as pending /// Sets an interrupt as pending
///
/// If the interrupt priority is high enough the interrupt will be serviced
/// immediately, otherwise it will be serviced at some point after the current
/// task ends.
pub fn set_pending<I>(interrupt: I) pub fn set_pending<I>(interrupt: I)
where where
I: Nr, I: Nr,