mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-27 14:04:56 +01:00
put async_after behind a Cargo feature
This commit is contained in:
parent
e34abea704
commit
9058a655dc
6 changed files with 267 additions and 71 deletions
30
Cargo.toml
30
Cargo.toml
|
@ -12,6 +12,35 @@ name = "cortex-m-rtfm"
|
|||
repository = "https://github.com/japaric/cortex-m-rtfm"
|
||||
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]
|
||||
cortex-m = "0.4.0"
|
||||
cortex-m-rtfm-macros = { path = "macros", version = "0.3.1" }
|
||||
|
@ -32,6 +61,7 @@ version = "0.9.0"
|
|||
|
||||
[features]
|
||||
cm7-r0p1 = ["cortex-m/cm7-r0p1"]
|
||||
timer-queue = ["cortex-m-rtfm-macros/timer-queue"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
@ -20,3 +20,6 @@ either = "1.5.0"
|
|||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[features]
|
||||
timer-queue = []
|
|
@ -1,7 +1,15 @@
|
|||
use syntax::check::App;
|
||||
use syntax::Result;
|
||||
|
||||
pub fn app(_app: &App) -> Result<()> {
|
||||
// TODO ???
|
||||
pub fn app(app: &App) -> Result<()> {
|
||||
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(())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
// 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.
|
||||
root.push(quote! {
|
||||
pub struct #__context<#lifetime> {
|
||||
pub async: #name::Async,
|
||||
pub baseline: u32,
|
||||
pub input: #input,
|
||||
pub resources: #name::Resources<#lifetime>,
|
||||
pub threshold: #hidden::#krate::Threshold<#name::Priority>,
|
||||
}
|
||||
if cfg!(feature = "timer-queue") {
|
||||
root.push(quote! {
|
||||
pub struct #__context<#lifetime> {
|
||||
pub async: #name::Async,
|
||||
pub baseline: u32,
|
||||
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(bl: #hidden::#krate::Instant, payload: #input) -> Self {
|
||||
#__context {
|
||||
async: #name::Async::new(bl),
|
||||
baseline: bl.into(),
|
||||
input: payload,
|
||||
resources: #name::Resources::new(),
|
||||
threshold: #hidden::#krate::Threshold::new(),
|
||||
#[allow(unsafe_code)]
|
||||
impl<#lifetime> #__context<#lifetime> {
|
||||
pub unsafe fn new(bl: #hidden::#krate::Instant, payload: #input) -> Self {
|
||||
#__context {
|
||||
async: #name::Async::new(bl),
|
||||
baseline: bl.into(),
|
||||
input: payload,
|
||||
resources: #name::Resources::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
|
||||
.iter()
|
||||
|
@ -163,7 +186,13 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
|
|||
|
||||
let async_exprs = task.async
|
||||
.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(
|
||||
task.async_after
|
||||
.iter()
|
||||
|
@ -189,15 +218,6 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
|
|||
#(#async_fields,)*
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
impl Async {
|
||||
pub unsafe fn new(_bl: #krate::Instant) -> Self {
|
||||
Async {
|
||||
#(#async_exprs,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub struct Resources<#lifetime> {
|
||||
#(#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 {
|
||||
Either::Left(interrupt) => {
|
||||
let export_name = interrupt.as_ref();
|
||||
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! {
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(unsafe_code)]
|
||||
#[export_name = #export_name]
|
||||
pub unsafe extern "C" fn #fn_name() {
|
||||
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]));
|
||||
|
||||
quote! {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct #name { baseline: #krate::Instant }
|
||||
if cfg!(feature = "timer-queue") {
|
||||
quote! {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct #name { baseline: #krate::Instant }
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
impl #name {
|
||||
pub unsafe fn new(bl: #krate::Instant) -> Self {
|
||||
#name { baseline: bl }
|
||||
#[allow(unsafe_code)]
|
||||
impl #name {
|
||||
pub unsafe fn new(bl: #krate::Instant) -> Self {
|
||||
#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`?
|
||||
#[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);
|
||||
#[allow(unsafe_code)]
|
||||
impl #name {
|
||||
pub unsafe fn new() -> Self {
|
||||
#name {}
|
||||
}
|
||||
|
||||
::#__priority::Q::new().claim_mut(t, |q, _| {
|
||||
q.split().0.enqueue_unchecked(tp);
|
||||
});
|
||||
// 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(payload)
|
||||
.tag(::#__priority::Task::#name);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(payload)
|
||||
::#__priority::Q::new().claim_mut(t, |q, _| {
|
||||
q.split().0.enqueue_unchecked(tp);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -537,14 +634,27 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
|
|||
.tasks()
|
||||
.iter()
|
||||
.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 => {
|
||||
let (bl, payload, slot) = payload.coerce().read();
|
||||
// NOTE(get) only `Slot` producer because a task can only be dispatched at one
|
||||
// priority
|
||||
#name::SQ::get().split().0.enqueue_unchecked(slot);
|
||||
#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<_>>();
|
||||
|
@ -640,7 +750,11 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
|
|||
let async_exprs = app.init
|
||||
.async
|
||||
.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(
|
||||
app.init
|
||||
.async_after
|
||||
|
@ -661,6 +775,21 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
|
|||
})
|
||||
.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! {
|
||||
#[allow(non_snake_case)]
|
||||
pub struct _ZN4init13LateResourcesE {
|
||||
|
@ -678,7 +807,7 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
|
|||
|
||||
pub struct Context {
|
||||
pub async: Async,
|
||||
pub baseline: u32,
|
||||
#baseline_field
|
||||
pub core: #krate::Core,
|
||||
pub device: Device,
|
||||
pub resources: Resources,
|
||||
|
@ -690,7 +819,7 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
|
|||
pub unsafe fn new(core: #krate::Core) -> Self {
|
||||
Context {
|
||||
async: Async::new(),
|
||||
baseline: 0,
|
||||
#baseline_expr
|
||||
core,
|
||||
device: Device::steal(),
|
||||
resources: Resources::new(),
|
||||
|
@ -706,7 +835,7 @@ pub fn app(ctxt: &Context, app: &App) -> Tokens {
|
|||
#[allow(unsafe_code)]
|
||||
impl Async {
|
||||
unsafe fn new() -> Self {
|
||||
let _bl = #krate::Instant::new(0);
|
||||
#bl
|
||||
|
||||
Async {
|
||||
#(#async_exprs,)*
|
||||
|
|
|
@ -15,6 +15,7 @@ extern crate typenum;
|
|||
mod instant;
|
||||
mod node;
|
||||
mod resource;
|
||||
#[cfg(feature = "timer-queue")]
|
||||
mod tq;
|
||||
|
||||
use core::mem;
|
||||
|
@ -38,6 +39,7 @@ pub use instant::Instant;
|
|||
pub use node::Node;
|
||||
use node::{Slot, TaggedPayload};
|
||||
pub use resource::{Resource, Threshold};
|
||||
#[cfg(feature = "timer-queue")]
|
||||
pub use tq::{dispatch, TimerQueue};
|
||||
|
||||
pub type PayloadQueue<T, N> = RingBuffer<TaggedPayload<T>, N, u8>;
|
||||
|
|
24
src/node.rs
24
src/node.rs
|
@ -9,24 +9,29 @@ pub struct Node<T>
|
|||
where
|
||||
T: 'static,
|
||||
{
|
||||
#[cfg(feature = "timer-queue")]
|
||||
baseline: Instant,
|
||||
payload: T,
|
||||
}
|
||||
|
||||
#[cfg(feature = "timer-queue")]
|
||||
impl<T> Eq for Node<T> {}
|
||||
|
||||
#[cfg(feature = "timer-queue")]
|
||||
impl<T> Ord for Node<T> {
|
||||
fn cmp(&self, rhs: &Self) -> Ordering {
|
||||
self.baseline.cmp(&rhs.baseline)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "timer-queue")]
|
||||
impl<T> PartialEq for Node<T> {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
self.baseline.eq(&rhs.baseline)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "timer-queue")]
|
||||
impl<T> PartialOrd for Node<T> {
|
||||
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
|
@ -42,11 +47,18 @@ where
|
|||
}
|
||||
|
||||
impl<T> Slot<T> {
|
||||
#[cfg(feature = "timer-queue")]
|
||||
pub fn write(self, bl: Instant, data: T) -> Payload<T> {
|
||||
self.node.baseline = bl;
|
||||
unsafe { ptr::write(&mut self.node.payload, data) }
|
||||
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> {
|
||||
|
@ -64,11 +76,18 @@ where
|
|||
}
|
||||
|
||||
impl<T> Payload<T> {
|
||||
#[cfg(feature = "timer-queue")]
|
||||
pub fn read(self) -> (Instant, T, Slot<T>) {
|
||||
let data = unsafe { ptr::read(&self.node.payload) };
|
||||
(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>
|
||||
where
|
||||
A: Copy,
|
||||
|
@ -97,6 +116,7 @@ where
|
|||
mem::transmute(self.payload)
|
||||
}
|
||||
|
||||
#[cfg(feature = "timer-queue")]
|
||||
pub fn baseline(&self) -> Instant {
|
||||
self.payload.node.baseline
|
||||
}
|
||||
|
@ -116,12 +136,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "timer-queue")]
|
||||
impl<T> Eq for TaggedPayload<T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
}
|
||||
|
||||
#[cfg(feature = "timer-queue")]
|
||||
impl<T> Ord for TaggedPayload<T>
|
||||
where
|
||||
T: Copy,
|
||||
|
@ -131,6 +153,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "timer-queue")]
|
||||
impl<T> PartialEq for TaggedPayload<T>
|
||||
where
|
||||
T: Copy,
|
||||
|
@ -140,6 +163,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "timer-queue")]
|
||||
impl<T> PartialOrd for TaggedPayload<T>
|
||||
where
|
||||
T: Copy,
|
||||
|
|
Loading…
Reference in a new issue