aboutsummaryrefslogtreecommitdiff
path: root/macros/src
diff options
context:
space:
mode:
authorGravatar homunkulus <homunkulus@gmx.com> 2017-12-23 10:36:08 +0000
committerGravatar homunkulus <homunkulus@gmx.com> 2017-12-23 10:36:08 +0000
commit8a396c51f2caaeca7ee0f81ef2f3c4f2f73d8df1 (patch)
treefa6538343f2d524be574285c2bb68057edc11420 /macros/src
parent0f5784c2401d4b12004f34345e721598fa21219a (diff)
parenta238fd5dc783f57f8fa61795690e6069b1becd32 (diff)
downloadrtic-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.rs7
-rw-r--r--macros/src/check.rs31
-rw-r--r--macros/src/trans.rs434
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) = (