Skip to content
Snippets Groups Projects
Commit a6dd0041 authored by Jorge Aparicio's avatar Jorge Aparicio
Browse files

implement the Resource trait for owned resources

this unbreaks the "generics" example
parent 219e1726
No related branches found
No related tags found
No related merge requests found
#![deny(unsafe_code)]
#![deny(warnings)]
#![feature(proc_macro)]
#![no_std]
extern crate cortex_m_rtfm as rtfm;
extern crate stm32f103xx;
use rtfm::{app, Threshold};
pub struct Foo;
app! {
device: stm32f103xx,
resources: {
static CO_OWNED: Foo = Foo;
static ON: Foo = Foo;
static OWNED: Foo = Foo;
static SHARED: Foo = Foo;
},
idle: {
resources: [OWNED, SHARED],
},
tasks: {
SYS_TICK: {
path: sys_tick,
resources: [CO_OWNED, ON, SHARED],
},
TIM2: {
enabled: false,
path: tim2,
priority: 1,
resources: [CO_OWNED],
},
},
}
fn init(_p: ::init::Peripherals, _r: ::init::Resources) {}
fn idle(_t: &mut Threshold, _r: ::idle::Resources) -> ! {
loop {}
}
fn sys_tick(_t: &mut Threshold, _r: SYS_TICK::Resources) {}
fn tim2(_t: &mut Threshold, _r: TIM2::Resources) {}
......@@ -73,12 +73,12 @@ mod main {
}
}
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
*r.ON = !*r.ON;
*r.CO_OWNED += 1;
}
fn tim2(_t: &mut Threshold, r: TIM2::Resources) {
fn tim2(_t: &mut Threshold, mut r: TIM2::Resources) {
*r.CO_OWNED += 1;
}
......@@ -70,5 +70,5 @@ fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
// This task has direct access to the resources
fn exti1(t: &mut Threshold, r: EXTI1::Resources) {
work(t, r.GPIOA, r.SPI1);
work(t, &r.GPIOA, &r.SPI1);
}
//! Demonstrates initialization of resources in `init`.
#![deny(unsafe_code)]
#![deny(warnings)]
#![feature(proc_macro)]
......
......@@ -77,7 +77,7 @@ fn idle() -> ! {
// `r` is the set of resources this task has access to. `SYS_TICK::Resources`
// has one field per resource declared in `app!`.
#[allow(unsafe_code)]
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
// toggle state
*r.ON = !*r.ON;
......
......@@ -42,7 +42,7 @@ fn idle() -> ! {
}
}
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
// ..
// This task can't be preempted by `tim2` so it has direct access to the
......
......@@ -42,7 +42,7 @@ fn idle() -> ! {
// As both tasks are running at the same priority one can't preempt the other.
// Thus both tasks have direct access to the resource
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
fn sys_tick(_t: &mut Threshold, mut r: SYS_TICK::Resources) {
// ..
*r.COUNTER += 1;
......@@ -50,7 +50,7 @@ fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
// ..
}
fn tim2(_t: &mut Threshold, r: TIM2::Resources) {
fn tim2(_t: &mut Threshold, mut r: TIM2::Resources) {
// ..
*r.COUNTER += 1;
......
......@@ -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,
......
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)]
......@@ -323,15 +402,15 @@ 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 resource = app.resources
.get(name)
.expect(&format!("BUG: resource {} has no definition", name));
let expr = &resource.expr;
let ty = &resource.ty;
......@@ -341,64 +420,71 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
},
None => quote! {
// Resource initialized in `init`
static mut #_name: #krate::UntaggedOption<#ty> = #krate::UntaggedOption { none: () };
static mut #_name: #krate::UntaggedOption<#ty> =
#krate::UntaggedOption { none: () };
},
});
}
}
let mut impl_items = vec![];
fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
let device = &app.device;
let krate = krate();
match *ownership {
Ownership::Owned { .. } => {
// For owned resources we don't need claim() or borrow()
}
Ownership::Shared { ceiling } => {
for (tname, task) in &app.tasks {
let mut exprs = vec![];
let mut fields = vec![];
let mut items = vec![];
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! {
items.push(quote! {
#[allow(non_camel_case_types)]
pub struct #rname { _0: PhantomData<*const ()> }
});
root.push(quote! {
#[allow(unsafe_code)]
unsafe impl #krate::Resource for #tname::#rname {
type Data = #ty;
fn borrow<'cs>(
&'cs self,
t: &'cs #krate::Threshold,
) -> &'cs #ty {
fn borrow<'cs>(&'cs self, t: &'cs Threshold) -> &'cs Self::Data {
assert!(t.value() >= #ceiling);
unsafe { &#res_rvalue }
unsafe { &#_static }
}
fn borrow_mut<'cs>(
&'cs mut self,
t: &'cs #krate::Threshold,
) -> &'cs mut #ty {
t: &'cs Threshold,
) -> &'cs mut Self::Data {
assert!(t.value() >= #ceiling);
unsafe {
&mut #res_rvalue
}
unsafe { &mut #_static }
}
fn claim<R, F>(
&self,
t: &mut #krate::Threshold,
f: F,
) -> R
fn claim<R, F>(&self, t: &mut Threshold, f: F) -> R
where
F: FnOnce(
&#ty,
&mut #krate::Threshold) -> R
F: FnOnce(&Self::Data, &mut Threshold) -> R
{
unsafe {
#krate::claim(
&#res_rvalue,
&#_static,
#ceiling,
#device::NVIC_PRIO_BITS,
t,
......@@ -407,19 +493,13 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
}
}
fn claim_mut<R, F>(
&mut self,
t: &mut #krate::Threshold,
f: F,
) -> R
fn claim_mut<R, F>(&mut self, t: &mut Threshold, f: F) -> R
where
F: FnOnce(
&mut #ty,
&mut #krate::Threshold) -> R
F: FnOnce(&mut Self::Data, &mut Threshold) -> R
{
unsafe {
#krate::claim(
&mut #res_rvalue,
&mut #_static,
#ceiling,
#device::NVIC_PRIO_BITS,
t,
......@@ -427,130 +507,48 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
)
}
}
});
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 ()> }
if ceiling <= task.priority {
root.push(quote! {
#[allow(unsafe_code)]
impl #name {
pub unsafe fn new() -> Self {
#name { _0: PhantomData }
}
}
});
}
impl core::ops::Deref for #tname::#rname {
type Target = #ty;
fn deref(&self) -> &Self::Target {
unsafe { &#_static }
}
}
if !items.is_empty() {
root.push(quote! {
#[allow(unsafe_code)]
mod _resource {
use core::marker::PhantomData;
#(#items)*
impl core::ops::DerefMut for #tname::#rname {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut #_static }
}
})
}
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,
pub #rname: #rname,
});
exprs.push(quote! {
#name: {
::_resource::#name::new()
},
#rname: #rname { _0: PhantomData },
});
}
_ => {
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 #ty,
});
exprs.push(if resource.expr.is_some() {
quote! {
#name: &mut ::#_name,
}
} else {
quote! {
#name: ::#_name.as_mut(),
}
});
}
}
}
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> {
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 +562,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 +574,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 +595,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) = (
......
......@@ -45,22 +45,24 @@ fn idle() -> ! {
}
fn exti0(mut t: &mut Threshold, mut r: EXTI0::Resources) {
// ERROR need to lock to access the resource because priority < ceiling
if *r.ON {
//~^ error type `EXTI0::ON` cannot be dereferenced
}
// OK need to lock to access the resource
if r.ON.claim(&mut t, |on, _| **on) {}
if r.ON.claim(&mut t, |on, _| *on) {}
// OK can claim a resource with maximum ceiling
r.MAX.claim_mut(&mut t, |max, _| **max += 1);
r.MAX.claim_mut(&mut t, |max, _| *max += 1);
}
fn exti1(mut t: &mut Threshold, r: EXTI1::Resources) {
// ERROR no need to lock. Has direct access because priority == ceiling
if (**r.ON).claim(&mut t, |on, _| **on) {
//~^ error no method named `claim` found for type
}
// OK to directly access the resource because priority == ceiling
if *r.ON {}
if **r.ON {
// OK
}
// though the resource can still be claimed -- the claim is a no-op
if r.ON.claim(&mut t, |on, _| *on) {}
}
fn exti2(_t: &mut Threshold, _r: EXTI2::Resources) {}
......@@ -9,7 +9,7 @@ extern crate stm32f103xx;
use rtfm::{app, Threshold};
app! { //~ error bound `rtfm::Threshold: core::marker::Send` is not satisfied
app! { //~ error bound `*const (): core::marker::Send` is not satisfied
device: stm32f103xx,
resources: {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment