diff options
author | 2017-12-23 10:36:08 +0000 | |
---|---|---|
committer | 2017-12-23 10:36:08 +0000 | |
commit | 8a396c51f2caaeca7ee0f81ef2f3c4f2f73d8df1 (patch) | |
tree | fa6538343f2d524be574285c2bb68057edc11420 /macros/src | |
parent | 0f5784c2401d4b12004f34345e721598fa21219a (diff) | |
parent | a238fd5dc783f57f8fa61795690e6069b1becd32 (diff) | |
download | rtic-8a396c51f2caaeca7ee0f81ef2f3c4f2f73d8df1.tar.gz rtic-8a396c51f2caaeca7ee0f81ef2f3c4f2f73d8df1.tar.zst rtic-8a396c51f2caaeca7ee0f81ef2f3c4f2f73d8df1.zip |
Auto merge of #58 - japaric:init-resources, r=japaric
safe `&'static mut` references via init.resources
see RFC #59 for details
Diffstat (limited to 'macros/src')
-rw-r--r-- | macros/src/analyze.rs | 7 | ||||
-rw-r--r-- | macros/src/check.rs | 31 | ||||
-rw-r--r-- | macros/src/trans.rs | 434 |
3 files changed, 261 insertions, 211 deletions
diff --git a/macros/src/analyze.rs b/macros/src/analyze.rs index 0fc125da..65d98e69 100644 --- a/macros/src/analyze.rs +++ b/macros/src/analyze.rs @@ -17,6 +17,13 @@ pub enum Ownership { } impl Ownership { + pub fn ceiling(&self) -> u8 { + match *self { + Ownership::Owned { priority } => priority, + Ownership::Shared { ceiling } => ceiling, + } + } + pub fn is_owned(&self) -> bool { match *self { Ownership::Owned { .. } => true, diff --git a/macros/src/check.rs b/macros/src/check.rs index 63cac1fa..f6fd9cc6 100644 --- a/macros/src/check.rs +++ b/macros/src/check.rs @@ -77,7 +77,38 @@ pub fn app(app: check::App) -> Result<App> { } fn resources(app: &App) -> Result<()> { + for name in &app.init.resources { + if let Some(resource) = app.resources.get(name) { + ensure!( + resource.expr.is_some(), + "resource `{}`, allocated to `init`, must have an initial value", + name + ); + } else { + bail!( + "resource `{}`, allocated to `init`, must be a data resource", + name + ); + } + + ensure!( + !app.idle.resources.contains(name), + "resources assigned to `init` can't be shared with `idle`" + ); + + ensure!( + app.tasks + .iter() + .all(|(_, task)| !task.resources.contains(name)), + "resources assigned to `init` can't be shared with tasks" + ) + } + for resource in app.resources.keys() { + if app.init.resources.contains(resource) { + continue; + } + if app.idle.resources.contains(resource) { continue; } diff --git a/macros/src/trans.rs b/macros/src/trans.rs index 9bf1e2a9..b50c73df 100644 --- a/macros/src/trans.rs +++ b/macros/src/trans.rs @@ -1,7 +1,7 @@ use quote::{Ident, Tokens}; use syn::{Lit, StrStyle}; -use analyze::{Ownership, Ownerships}; +use analyze::Ownerships; use check::{App, Kind}; fn krate() -> Ident { @@ -81,11 +81,11 @@ fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<Tokens>, root: &mut V }); } else { rfields.push(quote! { - pub #name: #super_::_resource::#name, + pub #name: ::idle::#name, }); rexprs.push(quote! { - #name: #super_::_resource::#name::new(), + #name: ::idle::#name { _0: core::marker::PhantomData }, }); } } @@ -126,6 +126,85 @@ fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<Tokens>, root: &mut V exprs.push(quote!(unsafe { idle::Resources::new() })); } + let device = &app.device; + for name in &app.idle.resources { + let ceiling = ownerships[name].ceiling(); + + // owned resource + if ceiling == 0 { + continue + } + + let _name = Ident::new(format!("_{}", name.as_ref())); + let resource = app.resources + .get(name) + .expect(&format!("BUG: resource {} has no definition", name)); + + let ty = &resource.ty; + let _static = if resource.expr.is_some() { + quote!(#_name) + } else { + quote!(#_name.some) + }; + + mod_items.push(quote! { + #[allow(non_camel_case_types)] + pub struct #name { _0: core::marker::PhantomData<*const ()> } + }); + + root.push(quote! { + #[allow(unsafe_code)] + unsafe impl #krate::Resource for idle::#name { + type Data = #ty; + + fn borrow<'cs>(&'cs self, t: &'cs Threshold) -> &'cs Self::Data { + assert!(t.value() >= #ceiling); + + unsafe { &#_static } + } + + fn borrow_mut<'cs>( + &'cs mut self, + t: &'cs Threshold, + ) -> &'cs mut Self::Data { + assert!(t.value() >= #ceiling); + + unsafe { &mut #_static } + } + + fn claim<R, F>(&self, t: &mut Threshold, f: F) -> R + where + F: FnOnce(&Self::Data, &mut Threshold) -> R + { + unsafe { + #krate::claim( + &#_static, + #ceiling, + #device::NVIC_PRIO_BITS, + t, + f, + ) + } + } + + fn claim_mut<R, F>(&mut self, t: &mut Threshold, f: F) -> R + where + F: FnOnce(&mut Self::Data, &mut Threshold) -> R + { + unsafe { + #krate::claim( + &mut #_static, + #ceiling, + #device::NVIC_PRIO_BITS, + t, + f, + ) + } + } + } + }); + } + if !mod_items.is_empty() { root.push(quote! { #[allow(unsafe_code)] @@ -170,18 +249,30 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) { let mut rexprs = vec![]; for (name, resource) in init_resources { - let _name = Ident::new(format!("_{}", name.as_ref())); - lifetime = Some(quote!('a)); - let ty = &resource.ty; - fields.push(quote! { - pub #name: &'a mut #krate::Static<#ty>, - }); + if app.init.resources.contains(name) { + fields.push(quote! { + pub #name: &'static mut #ty, + }); - rexprs.push(quote! { - #name: ::#krate::Static::ref_mut(&mut ::#_name), - }); + let expr = &resource.expr; + rexprs.push(quote!(#name: { + static mut #name: #ty = #expr; + &mut #name + },)); + } else { + let _name = Ident::new(format!("_{}", name.as_ref())); + lifetime = Some(quote!('a)); + + fields.push(quote! { + pub #name: &'a mut #ty, + }); + + rexprs.push(quote! { + #name: &mut ::#_name, + }); + } } root.push(quote! { @@ -323,234 +414,153 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) { fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { let krate = krate(); - let device = &app.device; - let mut items = vec![]; - let mut impls = vec![]; - for (name, ownership) in ownerships { + for name in ownerships.keys() { let _name = Ident::new(format!("_{}", name.as_ref())); - if let Some(resource) = app.resources.get(name) { - // Declare the static that holds the resource - let expr = &resource.expr; - let ty = &resource.ty; + // Declare the static that holds the resource + let resource = app.resources + .get(name) + .expect(&format!("BUG: resource {} has no definition", name)); + + let expr = &resource.expr; + let ty = &resource.ty; + + root.push(match *expr { + Some(ref expr) => quote! { + static mut #_name: #ty = #expr; + }, + None => quote! { + // Resource initialized in `init` + static mut #_name: #krate::UntaggedOption<#ty> = + #krate::UntaggedOption { none: () }; + }, + }); + } +} - root.push(match *expr { - Some(ref expr) => quote! { - static mut #_name: #ty = #expr; - }, - None => quote! { - // Resource initialized in `init` - static mut #_name: #krate::UntaggedOption<#ty> = #krate::UntaggedOption { none: () }; - }, - }); - } +fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { + let device = &app.device; + let krate = krate(); - let mut impl_items = vec![]; + for (tname, task) in &app.tasks { + let mut exprs = vec![]; + let mut fields = vec![]; + let mut items = vec![]; - match *ownership { - Ownership::Owned { .. } => { - // For owned resources we don't need claim() or borrow() - } - Ownership::Shared { ceiling } => { + let has_resources = !task.resources.is_empty(); + + if has_resources { + for rname in &task.resources { + let ceiling = ownerships[rname].ceiling(); + let _rname = Ident::new(format!("_{}", rname.as_ref())); let resource = app.resources - .get(name) - .expect(&format!("BUG: resource {} has no definition", name)); + .get(rname) + .expect(&format!("BUG: resource {} has no definition", rname)); + let ty = &resource.ty; - let res_rvalue = if resource.expr.is_some() { - quote!(#_name) + let _static = if resource.expr.is_some() { + quote!(#_rname) } else { - quote!(#_name.some) + quote!(#_rname.some) }; - impl_items.push(quote! { - type Data = #ty; - - fn borrow<'cs>( - &'cs self, - t: &'cs #krate::Threshold, - ) -> &'cs #krate::Static<#ty> { - assert!(t.value() >= #ceiling); + items.push(quote! { + #[allow(non_camel_case_types)] + pub struct #rname { _0: PhantomData<*const ()> } + }); - unsafe { #krate::Static::ref_(&#res_rvalue) } - } + root.push(quote! { + #[allow(unsafe_code)] + unsafe impl #krate::Resource for #tname::#rname { + type Data = #ty; - fn borrow_mut<'cs>( - &'cs mut self, - t: &'cs #krate::Threshold, - ) -> &'cs mut #krate::Static<#ty> { - assert!(t.value() >= #ceiling); + fn borrow<'cs>(&'cs self, t: &'cs Threshold) -> &'cs Self::Data { + assert!(t.value() >= #ceiling); - unsafe { - #krate::Static::ref_mut(&mut #res_rvalue) + unsafe { &#_static } } - } - fn claim<R, F>( - &self, - t: &mut #krate::Threshold, - f: F, - ) -> R - where - F: FnOnce( - &#krate::Static<#ty>, - &mut #krate::Threshold) -> R - { - unsafe { - #krate::claim( - #krate::Static::ref_(&#res_rvalue), - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) - } - } + fn borrow_mut<'cs>( + &'cs mut self, + t: &'cs Threshold, + ) -> &'cs mut Self::Data { + assert!(t.value() >= #ceiling); - fn claim_mut<R, F>( - &mut self, - t: &mut #krate::Threshold, - f: F, - ) -> R - where - F: FnOnce( - &mut #krate::Static<#ty>, - &mut #krate::Threshold) -> R - { - unsafe { - #krate::claim( - #krate::Static::ref_mut(&mut #res_rvalue), - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) + unsafe { &mut #_static } } - } - }); - - impls.push(quote! { - #[allow(unsafe_code)] - unsafe impl #krate::Resource for _resource::#name { - #(#impl_items)* - } - }); - items.push(quote! { - #[allow(non_camel_case_types)] - pub struct #name { _0: PhantomData<*const ()> } + fn claim<R, F>(&self, t: &mut Threshold, f: F) -> R + where + F: FnOnce(&Self::Data, &mut Threshold) -> R + { + unsafe { + #krate::claim( + &#_static, + #ceiling, + #device::NVIC_PRIO_BITS, + t, + f, + ) + } + } - #[allow(unsafe_code)] - impl #name { - pub unsafe fn new() -> Self { - #name { _0: PhantomData } + fn claim_mut<R, F>(&mut self, t: &mut Threshold, f: F) -> R + where + F: FnOnce(&mut Self::Data, &mut Threshold) -> R + { + unsafe { + #krate::claim( + &mut #_static, + #ceiling, + #device::NVIC_PRIO_BITS, + t, + f, + ) + } } } }); - } - } - } - - if !items.is_empty() { - root.push(quote! { - #[allow(unsafe_code)] - mod _resource { - use core::marker::PhantomData; - - #(#items)* - } - }) - } - root.push(quote! { - #(#impls)* - }); -} - -fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { - let device = &app.device; - let krate = krate(); - - for (name, task) in &app.tasks { - let mut exprs = vec![]; - let mut fields = vec![]; - let mut items = vec![]; - - let mut lifetime = None; - let mut needs_reexport = false; - let mut needs_threshold = false; - let has_resources = !task.resources.is_empty(); - - if has_resources { - needs_threshold = !task.resources.is_empty(); - for name in &task.resources { - let _name = Ident::new(format!("_{}", name.as_ref())); - - match ownerships[name] { - Ownership::Shared { ceiling } if ceiling > task.priority => { - needs_threshold = true; - - fields.push(quote! { - pub #name: ::_resource::#name, - }); + if ceiling <= task.priority { + root.push(quote! { + #[allow(unsafe_code)] + impl core::ops::Deref for #tname::#rname { + type Target = #ty; - exprs.push(quote! { - #name: { - ::_resource::#name::new() - }, - }); - } - _ => { - lifetime = Some(quote!('a)); - let resource = app.resources - .get(name) - .expect(&format!("BUG: resource {} has no definition", name)); - - needs_reexport = true; - let ty = &resource.ty; - - fields.push(quote! { - pub #name: &'a mut ::#krate::Static<#ty>, - }); - - exprs.push(if resource.expr.is_some() { - quote! { - #name: ::#krate::Static::ref_mut(&mut ::#_name), + fn deref(&self) -> &Self::Target { + unsafe { &#_static } } - } else { - quote! { - #name: ::#krate::Static::ref_mut(::#_name.as_mut()), + } + + #[allow(unsafe_code)] + impl core::ops::DerefMut for #tname::#rname { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut #_static } } - }); - } + } + }) } - } - 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)* - } + fields.push(quote! { + pub #rname: #rname, }); - items.push(quote! { - pub use ::#rname as Resources; - }); - } else { - items.push(quote! { - #[allow(non_snake_case)] - pub struct Resources<#lifetime> { - #(#fields)* - } + exprs.push(quote! { + #rname: #rname { _0: PhantomData }, }); } items.push(quote! { + #[allow(non_snake_case)] + pub struct Resources { + #(#fields)* + } + }); + + items.push(quote! { #[allow(unsafe_code)] - impl<#lifetime> Resources<#lifetime> { + impl Resources { pub unsafe fn new() -> Self { Resources { #(#exprs)* @@ -564,7 +574,7 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { let mut exprs = vec![]; let priority = task.priority; - if needs_threshold { + if has_resources { tys.push(quote!(&mut #krate::Threshold)); exprs.push(quote! { &mut if #priority == 1 << #device::NVIC_PRIO_BITS { @@ -576,18 +586,18 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { } if has_resources { - tys.push(quote!(#name::Resources)); - exprs.push(quote!(#name::Resources::new())); + tys.push(quote!(#tname::Resources)); + exprs.push(quote!(#tname::Resources::new())); } let path = &task.path; - let _name = Ident::new(format!("_{}", name)); - let export_name = Lit::Str(name.as_ref().to_owned(), StrStyle::Cooked); + let _tname = Ident::new(format!("_{}", tname)); + let export_name = Lit::Str(tname.as_ref().to_owned(), StrStyle::Cooked); root.push(quote! { #[allow(non_snake_case)] #[allow(unsafe_code)] #[export_name = #export_name] - pub unsafe extern "C" fn #_name() { + pub unsafe extern "C" fn #_tname() { let f: fn(#(#tys,)*) = #path; f(#(#exprs,)*) @@ -597,7 +607,9 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { root.push(quote!{ #[allow(non_snake_case)] #[allow(unsafe_code)] - mod #name { + mod #tname { + use core::marker::PhantomData; + #[allow(dead_code)] #[deny(const_err)] const CHECK_PRIORITY: (u8, u8) = ( |