put async_after behind a Cargo feature

This commit is contained in:
Jorge Aparicio 2018-05-01 15:29:13 +02:00
parent e34abea704
commit 9058a655dc
6 changed files with 267 additions and 71 deletions

View file

@ -12,6 +12,35 @@ name = "cortex-m-rtfm"
repository = "https://github.com/japaric/cortex-m-rtfm" repository = "https://github.com/japaric/cortex-m-rtfm"
version = "0.3.2" version = "0.3.2"
[[example]]
name = "async-after"
required-features = ["timer-queue"]
[[example]]
name = "async"
[[example]]
name = "empty"
[[example]]
name = "interrupt"
[[example]]
name = "periodic-payload"
required-features = ["timer-queue"]
[[example]]
name = "periodic-preemption-payload"
required-features = ["timer-queue"]
[[example]]
name = "periodic-preemption"
required-features = ["timer-queue"]
[[example]]
name = "periodic"
required-features = ["timer-queue"]
[dependencies] [dependencies]
cortex-m = "0.4.0" cortex-m = "0.4.0"
cortex-m-rtfm-macros = { path = "macros", version = "0.3.1" } cortex-m-rtfm-macros = { path = "macros", version = "0.3.1" }
@ -32,6 +61,7 @@ version = "0.9.0"
[features] [features]
cm7-r0p1 = ["cortex-m/cm7-r0p1"] cm7-r0p1 = ["cortex-m/cm7-r0p1"]
timer-queue = ["cortex-m-rtfm-macros/timer-queue"]
[profile.release] [profile.release]
lto = true lto = true

View file

@ -20,3 +20,6 @@ either = "1.5.0"
[lib] [lib]
proc-macro = true proc-macro = true
[features]
timer-queue = []

View file

@ -1,7 +1,15 @@
use syntax::check::App; use syntax::check::App;
use syntax::Result; use syntax::Result;
pub fn app(_app: &App) -> Result<()> { pub fn app(app: &App) -> Result<()> {
// TODO ??? if !cfg!(feature = "timer-queue") {
if !app.init.async_after.is_empty()
|| app.tasks.values().any(|task| !task.async_after.is_empty())
{
return Err(format_err!(
"async_after is not supported. Enable the 'timer-queue' feature to use it"
));
}
}
Ok(()) Ok(())
} }

View file

@ -108,28 +108,51 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
// primitive type and there's no way to import that type into a module (we don't know its // primitive type and there's no way to import that type into a module (we don't know its
// full path). So instead we just assume that `#input` has been imported in the root; this // full path). So instead we just assume that `#input` has been imported in the root; this
// forces us to put anything that refers to `#input` in the root. // forces us to put anything that refers to `#input` in the root.
root.push(quote! { if cfg!(feature = "timer-queue") {
pub struct #__context<#lifetime> { root.push(quote! {
pub async: #name::Async, pub struct #__context<#lifetime> {
pub baseline: u32, pub async: #name::Async,
pub input: #input, pub baseline: u32,
pub resources: #name::Resources<#lifetime>, pub input: #input,
pub threshold: #hidden::#krate::Threshold<#name::Priority>, pub resources: #name::Resources<#lifetime>,
} pub threshold: #hidden::#krate::Threshold<#name::Priority>,
}
#[allow(unsafe_code)] #[allow(unsafe_code)]
impl<#lifetime> #__context<#lifetime> { impl<#lifetime> #__context<#lifetime> {
pub unsafe fn new(bl: #hidden::#krate::Instant, payload: #input) -> Self { pub unsafe fn new(bl: #hidden::#krate::Instant, payload: #input) -> Self {
#__context { #__context {
async: #name::Async::new(bl), async: #name::Async::new(bl),
baseline: bl.into(), baseline: bl.into(),
input: payload, input: payload,
resources: #name::Resources::new(), resources: #name::Resources::new(),
threshold: #hidden::#krate::Threshold::new(), threshold: #hidden::#krate::Threshold::new(),
}
} }
} }
} });
}); } else {
root.push(quote! {
pub struct #__context<#lifetime> {
pub async: #name::Async,
pub input: #input,
pub resources: #name::Resources<#lifetime>,
pub threshold: #hidden::#krate::Threshold<#name::Priority>,
}
#[allow(unsafe_code)]
impl<#lifetime> #__context<#lifetime> {
pub unsafe fn new(payload: #input) -> Self {
#__context {
async: #name::Async::new(),
input: payload,
resources: #name::Resources::new(),
threshold: #hidden::#krate::Threshold::new(),
}
}
}
});
}
let res_fields = task.resources let res_fields = task.resources
.iter() .iter()
@ -163,7 +186,13 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
let async_exprs = task.async let async_exprs = task.async
.iter() .iter()
.map(|task| quote!(#task: ::__async::#task::new(_bl))) .map(|task| {
if cfg!(feature = "timer-queue") {
quote!(#task: ::__async::#task::new(_bl))
} else {
quote!(#task: ::__async::#task::new())
}
})
.chain( .chain(
task.async_after task.async_after
.iter() .iter()
@ -189,15 +218,6 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
#(#async_fields,)* #(#async_fields,)*
} }
#[allow(unsafe_code)]
impl Async {
pub unsafe fn new(_bl: #krate::Instant) -> Self {
Async {
#(#async_exprs,)*
}
}
}
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub struct Resources<#lifetime> { pub struct Resources<#lifetime> {
#(#res_fields,)* #(#res_fields,)*
@ -213,18 +233,49 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
} }
}); });
if cfg!(feature = "timer-queue") {
mod_.push(quote! {
#[allow(unsafe_code)]
impl Async {
pub unsafe fn new(_bl: #krate::Instant) -> Self {
Async {
#(#async_exprs,)*
}
}
}
});
} else {
mod_.push(quote! {
#[allow(unsafe_code)]
impl Async {
pub unsafe fn new() -> Self {
Async {
#(#async_exprs,)*
}
}
}
});
}
match task.interrupt_or_capacity { match task.interrupt_or_capacity {
Either::Left(interrupt) => { Either::Left(interrupt) => {
let export_name = interrupt.as_ref(); let export_name = interrupt.as_ref();
let fn_name = Ident::from(format!("__{}", interrupt)); let fn_name = Ident::from(format!("__{}", interrupt));
let bl = if cfg!(feature = "timer-queue") {
Some(quote!(#hidden::#krate::Instant::now(),))
} else {
None
};
root.push(quote! { root.push(quote! {
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[allow(unsafe_code)] #[allow(unsafe_code)]
#[export_name = #export_name] #[export_name = #export_name]
pub unsafe extern "C" fn #fn_name() { pub unsafe extern "C" fn #fn_name() {
let _ = #device::Interrupt::#interrupt; // verify that the interrupt exists let _ = #device::Interrupt::#interrupt; // verify that the interrupt exists
#name::HANDLER(#name::Context::new(#hidden::#krate::Instant::now(), ())) #name::HANDLER(#name::Context::new(#bl ()))
} }
}); });
} }
@ -293,44 +344,90 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
)); ));
let qc = Ident::from(format!("U{}", ctxt.ceilings.dispatch_queues()[&priority])); let qc = Ident::from(format!("U{}", ctxt.ceilings.dispatch_queues()[&priority]));
quote! { if cfg!(feature = "timer-queue") {
#[allow(non_camel_case_types)] quote! {
pub struct #name { baseline: #krate::Instant } #[allow(non_camel_case_types)]
pub struct #name { baseline: #krate::Instant }
#[allow(unsafe_code)] #[allow(unsafe_code)]
impl #name { impl #name {
pub unsafe fn new(bl: #krate::Instant) -> Self { pub unsafe fn new(bl: #krate::Instant) -> Self {
#name { baseline: bl } #name { baseline: bl }
}
// XXX or take `self`?
#[inline]
pub fn post<P>(
&self,
t: &mut #krate::Threshold<P>,
payload: #ty,
) -> Result<(), #ty>
where
P: #krate::Unsigned +
#krate::Max<#krate::#sqc> +
#krate::Max<#krate::#qc>,
#krate::Maximum<P, #krate::#sqc>: #krate::Unsigned,
#krate::Maximum<P, #krate::#qc>: #krate::Unsigned,
{
unsafe {
if let Some(slot) =
::#name::SQ::new().claim_mut(t, |sq, _| sq.dequeue()) {
let tp = slot
.write(self.baseline, payload)
.tag(::#__priority::Task::#name);
::#__priority::Q::new().claim_mut(t, |q, _| {
q.split().0.enqueue_unchecked(tp);
});
Ok(())
} else {
Err(payload)
}
}
}
} }
}
} else {
quote! {
#[allow(non_camel_case_types)]
pub struct #name {}
// XXX or take `self`? #[allow(unsafe_code)]
#[inline] impl #name {
pub fn post<P>( pub unsafe fn new() -> Self {
&self, #name {}
t: &mut #krate::Threshold<P>, }
payload: #ty,
) -> Result<(), #ty>
where
P: #krate::Unsigned +
#krate::Max<#krate::#sqc> +
#krate::Max<#krate::#qc>,
#krate::Maximum<P, #krate::#sqc>: #krate::Unsigned,
#krate::Maximum<P, #krate::#qc>: #krate::Unsigned,
{
unsafe {
if let Some(slot) =
::#name::SQ::new().claim_mut(t, |sq, _| sq.dequeue()) {
let tp = slot
.write(self.baseline, payload)
.tag(::#__priority::Task::#name);
::#__priority::Q::new().claim_mut(t, |q, _| { // XXX or take `self`?
q.split().0.enqueue_unchecked(tp); #[inline]
}); pub fn post<P>(
&self,
t: &mut #krate::Threshold<P>,
payload: #ty,
) -> Result<(), #ty>
where
P: #krate::Unsigned +
#krate::Max<#krate::#sqc> +
#krate::Max<#krate::#qc>,
#krate::Maximum<P, #krate::#sqc>: #krate::Unsigned,
#krate::Maximum<P, #krate::#qc>: #krate::Unsigned,
{
unsafe {
if let Some(slot) =
::#name::SQ::new().claim_mut(t, |sq, _| sq.dequeue()) {
let tp = slot
.write(payload)
.tag(::#__priority::Task::#name);
Ok(()) ::#__priority::Q::new().claim_mut(t, |q, _| {
} else { q.split().0.enqueue_unchecked(tp);
Err(payload) });
Ok(())
} else {
Err(payload)
}
} }
} }
} }
@ -537,14 +634,27 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
.tasks() .tasks()
.iter() .iter()
.map(|name| { .map(|name| {
quote! { // NOTE(get) this is the only `Slot` producer because a task can only be
// dispatched at one priority
if cfg!(feature = "timer-queue") {
quote! {
#__priority::Task::#name => { #__priority::Task::#name => {
let (bl, payload, slot) = payload.coerce().read(); let (bl, payload, slot) = payload.coerce().read();
// NOTE(get) only `Slot` producer because a task can only be dispatched at one
// priority // priority
#name::SQ::get().split().0.enqueue_unchecked(slot); #name::SQ::get().split().0.enqueue_unchecked(slot);
#name::HANDLER(#name::Context::new(bl, payload)); #name::HANDLER(#name::Context::new(bl, payload));
} }
}
} else {
quote! {
#__priority::Task::#name => {
let (payload, slot) = payload.coerce().read();
// priority
#name::SQ::get().split().0.enqueue_unchecked(slot);
#name::HANDLER(#name::Context::new(payload));
}
}
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -640,7 +750,11 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
let async_exprs = app.init let async_exprs = app.init
.async .async
.iter() .iter()
.map(|task| quote!(#task: ::__async::#task::new(_bl))) .map(|task| if cfg!(feature = "timer-queue") {
quote!(#task: ::__async::#task::new(_bl))
} else {
quote!(#task: ::__async::#task::new())
})
.chain( .chain(
app.init app.init
.async_after .async_after
@ -661,6 +775,21 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let bl = if cfg!(feature = "timer-queue") {
Some(quote!(let _bl = #krate::Instant::new(0);))
} else {
None
};
let baseline_field = if cfg!(feature = "timer-queue") {
Some(quote!(pub baseline: u32,))
} else {
None
};
let baseline_expr = if cfg!(feature = "timer-queue") {
Some(quote!(baseline: 0,))
} else {
None
};
root.push(quote! { root.push(quote! {
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub struct _ZN4init13LateResourcesE { pub struct _ZN4init13LateResourcesE {
@ -678,7 +807,7 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
pub struct Context { pub struct Context {
pub async: Async, pub async: Async,
pub baseline: u32, #baseline_field
pub core: #krate::Core, pub core: #krate::Core,
pub device: Device, pub device: Device,
pub resources: Resources, pub resources: Resources,
@ -690,7 +819,7 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
pub unsafe fn new(core: #krate::Core) -> Self { pub unsafe fn new(core: #krate::Core) -> Self {
Context { Context {
async: Async::new(), async: Async::new(),
baseline: 0, #baseline_expr
core, core,
device: Device::steal(), device: Device::steal(),
resources: Resources::new(), resources: Resources::new(),
@ -706,7 +835,7 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
#[allow(unsafe_code)] #[allow(unsafe_code)]
impl Async { impl Async {
unsafe fn new() -> Self { unsafe fn new() -> Self {
let _bl = #krate::Instant::new(0); #bl
Async { Async {
#(#async_exprs,)* #(#async_exprs,)*

View file

@ -15,6 +15,7 @@ extern crate typenum;
mod instant; mod instant;
mod node; mod node;
mod resource; mod resource;
#[cfg(feature = "timer-queue")]
mod tq; mod tq;
use core::mem; use core::mem;
@ -38,6 +39,7 @@ pub use instant::Instant;
pub use node::Node; pub use node::Node;
use node::{Slot, TaggedPayload}; use node::{Slot, TaggedPayload};
pub use resource::{Resource, Threshold}; pub use resource::{Resource, Threshold};
#[cfg(feature = "timer-queue")]
pub use tq::{dispatch, TimerQueue}; pub use tq::{dispatch, TimerQueue};
pub type PayloadQueue<T, N> = RingBuffer<TaggedPayload<T>, N, u8>; pub type PayloadQueue<T, N> = RingBuffer<TaggedPayload<T>, N, u8>;

View file

@ -9,24 +9,29 @@ pub struct Node<T>
where where
T: 'static, T: 'static,
{ {
#[cfg(feature = "timer-queue")]
baseline: Instant, baseline: Instant,
payload: T, payload: T,
} }
#[cfg(feature = "timer-queue")]
impl<T> Eq for Node<T> {} impl<T> Eq for Node<T> {}
#[cfg(feature = "timer-queue")]
impl<T> Ord for Node<T> { impl<T> Ord for Node<T> {
fn cmp(&self, rhs: &Self) -> Ordering { fn cmp(&self, rhs: &Self) -> Ordering {
self.baseline.cmp(&rhs.baseline) self.baseline.cmp(&rhs.baseline)
} }
} }
#[cfg(feature = "timer-queue")]
impl<T> PartialEq for Node<T> { impl<T> PartialEq for Node<T> {
fn eq(&self, rhs: &Self) -> bool { fn eq(&self, rhs: &Self) -> bool {
self.baseline.eq(&rhs.baseline) self.baseline.eq(&rhs.baseline)
} }
} }
#[cfg(feature = "timer-queue")]
impl<T> PartialOrd for Node<T> { impl<T> PartialOrd for Node<T> {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> { fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
Some(self.cmp(rhs)) Some(self.cmp(rhs))
@ -42,11 +47,18 @@ where
} }
impl<T> Slot<T> { impl<T> Slot<T> {
#[cfg(feature = "timer-queue")]
pub fn write(self, bl: Instant, data: T) -> Payload<T> { pub fn write(self, bl: Instant, data: T) -> Payload<T> {
self.node.baseline = bl; self.node.baseline = bl;
unsafe { ptr::write(&mut self.node.payload, data) } unsafe { ptr::write(&mut self.node.payload, data) }
Payload { node: self.node } Payload { node: self.node }
} }
#[cfg(not(feature = "timer-queue"))]
pub fn write(self, data: T) -> Payload<T> {
unsafe { ptr::write(&mut self.node.payload, data) }
Payload { node: self.node }
}
} }
impl<T> Into<Slot<T>> for &'static mut Node<T> { impl<T> Into<Slot<T>> for &'static mut Node<T> {
@ -64,11 +76,18 @@ where
} }
impl<T> Payload<T> { impl<T> Payload<T> {
#[cfg(feature = "timer-queue")]
pub fn read(self) -> (Instant, T, Slot<T>) { pub fn read(self) -> (Instant, T, Slot<T>) {
let data = unsafe { ptr::read(&self.node.payload) }; let data = unsafe { ptr::read(&self.node.payload) };
(self.node.baseline, data, Slot { node: self.node }) (self.node.baseline, data, Slot { node: self.node })
} }
#[cfg(not(feature = "timer-queue"))]
pub fn read(self) -> (T, Slot<T>) {
let data = unsafe { ptr::read(&self.node.payload) };
(data, Slot { node: self.node })
}
pub fn tag<A>(self, tag: A) -> TaggedPayload<A> pub fn tag<A>(self, tag: A) -> TaggedPayload<A>
where where
A: Copy, A: Copy,
@ -97,6 +116,7 @@ where
mem::transmute(self.payload) mem::transmute(self.payload)
} }
#[cfg(feature = "timer-queue")]
pub fn baseline(&self) -> Instant { pub fn baseline(&self) -> Instant {
self.payload.node.baseline self.payload.node.baseline
} }
@ -116,12 +136,14 @@ where
} }
} }
#[cfg(feature = "timer-queue")]
impl<T> Eq for TaggedPayload<T> impl<T> Eq for TaggedPayload<T>
where where
T: Copy, T: Copy,
{ {
} }
#[cfg(feature = "timer-queue")]
impl<T> Ord for TaggedPayload<T> impl<T> Ord for TaggedPayload<T>
where where
T: Copy, T: Copy,
@ -131,6 +153,7 @@ where
} }
} }
#[cfg(feature = "timer-queue")]
impl<T> PartialEq for TaggedPayload<T> impl<T> PartialEq for TaggedPayload<T>
where where
T: Copy, T: Copy,
@ -140,6 +163,7 @@ where
} }
} }
#[cfg(feature = "timer-queue")]
impl<T> PartialOrd for TaggedPayload<T> impl<T> PartialOrd for TaggedPayload<T>
where where
T: Copy, T: Copy,