mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-25 03:19:34 +01:00
Merge #469
469: Goodbye static mut r=AfoHT a=korken89
Squashed and updated version of @perlindgren branch.
In release there are 0 bytes difference for all examples 🎉
For debug we see a bloat of ~1-2% worst case, commonly less.
Complete diff of sizes for all examples (first is goodbye static mut, second is master):
```
< 27220 0 28 27248 6a70 spawn
---
> 27092 0 28 27120 69f0 spawn
< 16916 0 44 16960 4240 late
---
> 16836 0 44 16880 41f0 late
< 15952 0 12 15964 3e5c type-usage
---
> 15872 0 12 15884 3e0c type-usage
< 22068 0 44 22112 5660 cfg
---
> 21812 0 44 21856 5560 cfg
< 34784 0 40 34824 8808 periodic
---
> 34496 0 40 34536 86e8 periodic
< 22308 0 32 22340 5744 task
---
> 21972 0 32 22004 55f4 task
< 15076 8 24 15108 3b04 task-local
---
> 14980 8 24 15012 3aa4 task-local
< 12884 0 24 12908 326c destructure
---
> 12820 0 24 12844 322c destructure
< 10128 0 16 10144 27a0 init
---
> 10112 0 16 10128 2790 init
< 19044 0 20 19064 4a78 task_named_main
---
> 18916 0 20 18936 49f8 task_named_main
< 27252 0 28 27280 6a90 extern_spawn
---
> 27124 0 28 27152 6a10 extern_spawn
< 10176 0 16 10192 27d0 idle
---
> 10160 0 16 10176 27c0 idle
< 13972 0 16 13988 36a4 resource
---
> 13940 0 16 13956 3684 resource
< 16228 0 24 16252 3f7c multilock
---
> 16116 0 24 16140 3f0c multilock
< 14660 0 16 14676 3954 lock
---
> 14628 0 16 14644 3934 lock
< 10416 0 16 10432 28c0 task-local-minimal
---
> 10400 0 16 10416 28b0 task-local-minimal
< 14164 0 24 14188 376c generics
---
> 14148 0 24 14172 375c generics
< 30644 0 48 30692 77e4 message
---
> 30308 0 48 30356 7694 message
< 28964 0 36 29000 7148 spawn2
---
> 28724 0 36 28760 7058 spawn2
< 15952 0 8 15960 3e58 t-schedule-core-stable
---
> 15872 0 8 15880 3e08 t-schedule-core-stable
< 17408 0 20 17428 4414 t-cfg
---
> 17248 0 20 17268 4374 t-cfg
< 12948 0 16 12964 32a4 hardware
---
> 12932 0 16 12948 3294 hardware
< 54640 0 104 54744 d5d8 t-schedule
---
> 53696 0 104 53800 d228 t-schedule
< 26132 0 548 26680 6838 pool
---
> 25876 0 548 26424 6738 pool
< 22372 0 56 22428 579c cfg-whole-task
---
> 22100 0 56 22156 568c cfg-whole-task
< 38292 0 76 38368 95e0 schedule
---
> 37828 0 76 37904 9410 schedule
< 21216 0 32 21248 5300 t-spawn
---
> 20880 0 32 20912 51b0 t-spawn
< 22820 0 56 22876 595c capacity
---
> 22580 0 56 22636 586c capacity
< 17060 0 48 17108 42d4 static
---
> 16980 0 48 17028 4284 static
< 20288 0 24 20312 4f58 ramfunc
---
> 20096 0 24 20120 4e98 ramfunc
< 11760 0 20 11780 2e04 t-resource
---
> 11664 0 20 11684 2da4 t-resource
< 13028 0 16 13044 32f4 only-shared-access
---
> 13012 0 16 13028 32e4 only-shared-access
< 16576 0 16 16592 40d0 not-sync
---
> 16432 0 16 16448 4040 not-sync
< 13892 0 16 13908 3654 resource-user-struct
---
> 13860 0 16 13876 3634 resource-user-struct
< 37472 0 64 37536 92a0 double_schedule
---
> 36960 0 64 37024 90a0 double_schedule
< 17648 0 8 17656 44f8 t-stask-main
---
> 17520 0 8 17528 4478 t-stask-main
< 8816 0 4 8820 2274 t-late-not-send
---
> 8800 0 4 8804 2264 t-late-not-send
< 23280 0 32 23312 5b10 types
---
> 23120 0 32 23152 5a70 types
```
Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
This commit is contained in:
commit
aad8f81991
11 changed files with 156 additions and 59 deletions
|
@ -141,7 +141,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
|
||||||
rtic::export::interrupt::free(|_| {
|
rtic::export::interrupt::free(|_| {
|
||||||
use rtic::Monotonic as _;
|
use rtic::Monotonic as _;
|
||||||
use rtic::time::Clock as _;
|
use rtic::time::Clock as _;
|
||||||
if let Some(m) = unsafe{ #app_path::#ident.as_ref() } {
|
if let Some(m) = unsafe{ #app_path::#ident.get_mut_unchecked() } {
|
||||||
if let Ok(v) = m.try_now() {
|
if let Ok(v) = m.try_now() {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// For future use
|
||||||
// let doc = format!(
|
// let doc = format!(
|
||||||
// "Software tasks to be dispatched at priority level {}",
|
// "Software tasks to be dispatched at priority level {}",
|
||||||
// level,
|
// level,
|
||||||
|
@ -53,13 +54,14 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For future use
|
||||||
// let doc = format!(
|
// let doc = format!(
|
||||||
// "Queue of tasks ready to be dispatched at priority level {}",
|
// "Queue of tasks ready to be dispatched at priority level {}",
|
||||||
// level
|
// level
|
||||||
// );
|
// );
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
static mut #rq: #rq_ty = #rq_expr;
|
static #rq: rtic::RacyCell<#rq_ty> = rtic::RacyCell::new(#rq_expr);
|
||||||
));
|
));
|
||||||
|
|
||||||
let arms = channel
|
let arms = channel
|
||||||
|
@ -86,8 +88,12 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#t::#name => {
|
#t::#name => {
|
||||||
let #tupled =
|
let #tupled =
|
||||||
#inputs.get_unchecked(usize::from(index)).as_ptr().read();
|
#inputs
|
||||||
#fq.split().0.enqueue_unchecked(index);
|
.get_unchecked()
|
||||||
|
.get_unchecked(usize::from(index))
|
||||||
|
.as_ptr()
|
||||||
|
.read();
|
||||||
|
#fq.get_mut_unchecked().split().0.enqueue_unchecked(index);
|
||||||
let priority = &rtic::export::Priority::new(PRIORITY);
|
let priority = &rtic::export::Priority::new(PRIORITY);
|
||||||
#app_path::#name(
|
#app_path::#name(
|
||||||
#locals_new
|
#locals_new
|
||||||
|
@ -100,7 +106,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
stmts.push(quote!(
|
stmts.push(quote!(
|
||||||
while let Some((task, index)) = #rq.split().1.dequeue() {
|
while let Some((task, index)) = #rq.get_mut_unchecked().split().1.dequeue() {
|
||||||
match task {
|
match task {
|
||||||
#(#arms)*
|
#(#arms)*
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,11 +50,11 @@ pub fn codegen(
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
static mut #name: #ty = #expr
|
static #name: rtic::RacyCell<#ty> = rtic::RacyCell::new(#expr)
|
||||||
));
|
));
|
||||||
values.push(quote!(
|
values.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#name: &mut #name
|
#name: #name.get_mut_unchecked()
|
||||||
));
|
));
|
||||||
names.push(name);
|
names.push(name);
|
||||||
pats.push(quote!(
|
pats.push(quote!(
|
||||||
|
@ -64,7 +64,7 @@ pub fn codegen(
|
||||||
}
|
}
|
||||||
|
|
||||||
if lt.is_some() && has_cfgs {
|
if lt.is_some() && has_cfgs {
|
||||||
fields.push(quote!(__marker__: core::marker::PhantomData<&'a mut ()>));
|
fields.push(quote!(__marker__: core::marker::PhantomData<&'a ()>));
|
||||||
values.push(quote!(__marker__: core::marker::PhantomData));
|
values.push(quote!(__marker__: core::marker::PhantomData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,14 +245,15 @@ pub fn codegen(
|
||||||
let input = #tupled;
|
let input = #tupled;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
|
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.get_mut_unchecked().dequeue()) {
|
||||||
#app_path::#inputs
|
#app_path::#inputs
|
||||||
|
.get_mut_unchecked()
|
||||||
.get_unchecked_mut(usize::from(index))
|
.get_unchecked_mut(usize::from(index))
|
||||||
.as_mut_ptr()
|
.as_mut_ptr()
|
||||||
.write(input);
|
.write(input);
|
||||||
|
|
||||||
rtic::export::interrupt::free(|_| {
|
rtic::export::interrupt::free(|_| {
|
||||||
#app_path::#rq.enqueue_unchecked((#app_path::#t::#name, index));
|
#app_path::#rq.get_mut_unchecked().enqueue_unchecked((#app_path::#t::#name, index));
|
||||||
});
|
});
|
||||||
|
|
||||||
rtic::pend(#device::#enum_::#interrupt);
|
rtic::pend(#device::#enum_::#interrupt);
|
||||||
|
@ -304,6 +305,10 @@ pub fn codegen(
|
||||||
let user_imports = &app.user_imports;
|
let user_imports = &app.user_imports;
|
||||||
let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
|
let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
|
||||||
|
|
||||||
|
// For future use
|
||||||
|
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
|
||||||
|
// items.push(quote!(#[doc = #doc]));
|
||||||
|
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
/// Holds methods related to this monotonic
|
/// Holds methods related to this monotonic
|
||||||
pub mod #m {
|
pub mod #m {
|
||||||
|
@ -325,12 +330,16 @@ pub fn codegen(
|
||||||
impl SpawnHandle {
|
impl SpawnHandle {
|
||||||
pub fn cancel(self) -> Result<#ty, ()> {
|
pub fn cancel(self) -> Result<#ty, ()> {
|
||||||
rtic::export::interrupt::free(|_| unsafe {
|
rtic::export::interrupt::free(|_| unsafe {
|
||||||
let tq = &mut *#app_path::#tq.as_mut_ptr();
|
let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr();
|
||||||
if let Some((_task, index)) = tq.cancel_marker(self.marker) {
|
if let Some((_task, index)) = tq.cancel_marker(self.marker) {
|
||||||
// Get the message
|
// Get the message
|
||||||
let msg = #app_path::#inputs.get_unchecked(usize::from(index)).as_ptr().read();
|
let msg = #app_path::#inputs
|
||||||
|
.get_unchecked()
|
||||||
|
.get_unchecked(usize::from(index))
|
||||||
|
.as_ptr()
|
||||||
|
.read();
|
||||||
// Return the index to the free queue
|
// Return the index to the free queue
|
||||||
#app_path::#fq.split().0.enqueue_unchecked(index);
|
#app_path::#fq.get_mut_unchecked().split().0.enqueue_unchecked(index);
|
||||||
|
|
||||||
Ok(msg)
|
Ok(msg)
|
||||||
} else {
|
} else {
|
||||||
|
@ -350,10 +359,10 @@ pub fn codegen(
|
||||||
pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result<Self, ()>
|
pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result<Self, ()>
|
||||||
{
|
{
|
||||||
rtic::export::interrupt::free(|_| unsafe {
|
rtic::export::interrupt::free(|_| unsafe {
|
||||||
let marker = #tq_marker;
|
let marker = *#tq_marker.get_mut_unchecked();
|
||||||
#tq_marker = #tq_marker.wrapping_add(1);
|
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
|
||||||
|
|
||||||
let tq = &mut *#app_path::#tq.as_mut_ptr();
|
let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr();
|
||||||
|
|
||||||
tq.update_marker(self.marker, marker, instant, || #pend).map(|_| SpawnHandle { marker })
|
tq.update_marker(self.marker, marker, instant, || #pend).map(|_| SpawnHandle { marker })
|
||||||
})
|
})
|
||||||
|
@ -373,7 +382,7 @@ pub fn codegen(
|
||||||
D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
|
D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
|
||||||
{
|
{
|
||||||
|
|
||||||
let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.is_none() }) {
|
let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.get_mut_unchecked().is_none() }) {
|
||||||
rtic::time::Instant::new(0)
|
rtic::time::Instant::new(0)
|
||||||
} else {
|
} else {
|
||||||
#app_path::monotonics::#m::now()
|
#app_path::monotonics::#m::now()
|
||||||
|
@ -390,19 +399,21 @@ pub fn codegen(
|
||||||
) -> Result<SpawnHandle, #ty> {
|
) -> Result<SpawnHandle, #ty> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let input = #tupled;
|
let input = #tupled;
|
||||||
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
|
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.get_mut_unchecked().dequeue()) {
|
||||||
#app_path::#inputs
|
#app_path::#inputs
|
||||||
|
.get_mut_unchecked()
|
||||||
.get_unchecked_mut(usize::from(index))
|
.get_unchecked_mut(usize::from(index))
|
||||||
.as_mut_ptr()
|
.as_mut_ptr()
|
||||||
.write(input);
|
.write(input);
|
||||||
|
|
||||||
#app_path::#instants
|
#app_path::#instants
|
||||||
|
.get_mut_unchecked()
|
||||||
.get_unchecked_mut(usize::from(index))
|
.get_unchecked_mut(usize::from(index))
|
||||||
.as_mut_ptr()
|
.as_mut_ptr()
|
||||||
.write(instant);
|
.write(instant);
|
||||||
|
|
||||||
rtic::export::interrupt::free(|_| {
|
rtic::export::interrupt::free(|_| {
|
||||||
let marker = #tq_marker;
|
let marker = *#tq_marker.get_mut_unchecked();
|
||||||
let nr = rtic::export::NotReady {
|
let nr = rtic::export::NotReady {
|
||||||
instant,
|
instant,
|
||||||
index,
|
index,
|
||||||
|
@ -410,15 +421,15 @@ pub fn codegen(
|
||||||
marker,
|
marker,
|
||||||
};
|
};
|
||||||
|
|
||||||
#tq_marker = #tq_marker.wrapping_add(1);
|
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
|
||||||
|
|
||||||
let tq = unsafe { &mut *#app_path::#tq.as_mut_ptr() };
|
let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr();
|
||||||
|
|
||||||
tq.enqueue_unchecked(
|
tq.enqueue_unchecked(
|
||||||
nr,
|
nr,
|
||||||
|| #enable_interrupt,
|
|| #enable_interrupt,
|
||||||
|| #pend,
|
|| #pend,
|
||||||
#app_path::#m_ident.as_mut());
|
#app_path::#m_ident.get_mut_unchecked().as_mut());
|
||||||
|
|
||||||
Ok(SpawnHandle { marker })
|
Ok(SpawnHandle { marker })
|
||||||
})
|
})
|
||||||
|
|
|
@ -17,16 +17,24 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
|
||||||
// If it's live
|
// If it's live
|
||||||
let cfgs = app.late_resources[name].cfgs.clone();
|
let cfgs = app.late_resources[name].cfgs.clone();
|
||||||
if analysis.locations.get(name).is_some() {
|
if analysis.locations.get(name).is_some() {
|
||||||
// Need to also include the cfgs
|
|
||||||
stmts.push(quote!(
|
stmts.push(quote!(
|
||||||
#(#cfgs)*
|
// We include the cfgs
|
||||||
#mangled_name.as_mut_ptr().write(late.#name);
|
#(#cfgs)*
|
||||||
|
// Late resource is a RacyCell<MaybeUninit<T>>
|
||||||
|
// - `get_mut_unchecked` to obtain `MaybeUninit<T>`
|
||||||
|
// - `as_mut_ptr` to obtain a raw pointer to `MaybeUninit<T>`
|
||||||
|
// - `write` the defined value for the late resource T
|
||||||
|
#mangled_name.get_mut_unchecked().as_mut_ptr().write(late.#name);
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, (monotonic, _)) in app.monotonics.iter().enumerate() {
|
for (i, (monotonic, _)) in app.monotonics.iter().enumerate() {
|
||||||
|
// For future use
|
||||||
|
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
|
||||||
|
// stmts.push(quote!(#[doc = #doc]));
|
||||||
|
|
||||||
let idx = Index {
|
let idx = Index {
|
||||||
index: i as u32,
|
index: i as u32,
|
||||||
span: Span::call_site(),
|
span: Span::call_site(),
|
||||||
|
@ -36,7 +44,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
|
||||||
// Store the monotonic
|
// Store the monotonic
|
||||||
let name = util::monotonic_ident(&monotonic.to_string());
|
let name = util::monotonic_ident(&monotonic.to_string());
|
||||||
let name = util::mark_internal_ident(&name);
|
let name = util::mark_internal_ident(&name);
|
||||||
stmts.push(quote!(#name = Some(monotonics.#idx);));
|
stmts.push(quote!(*#name.get_mut_unchecked() = Some(monotonics.#idx);));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable the interrupts -- this completes the `init`-ialization phase
|
// Enable the interrupts -- this completes the `init`-ialization phase
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
||||||
let fq_ident = util::mark_internal_ident(&fq_ident);
|
let fq_ident = util::mark_internal_ident(&fq_ident);
|
||||||
|
|
||||||
stmts.push(quote!(
|
stmts.push(quote!(
|
||||||
(0..#cap).for_each(|i| #fq_ident.enqueue_unchecked(i));
|
(0..#cap).for_each(|i| #fq_ident.get_mut_unchecked().enqueue_unchecked(i));
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,9 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
|
||||||
let tq = util::mark_internal_ident(&tq);
|
let tq = util::mark_internal_ident(&tq);
|
||||||
|
|
||||||
// Initialize timer queues
|
// Initialize timer queues
|
||||||
stmts.push(quote!(#tq.as_mut_ptr().write(rtic::export::TimerQueue::new());));
|
stmts.push(
|
||||||
|
quote!(#tq.get_mut_unchecked().as_mut_ptr().write(rtic::export::TimerQueue::new());),
|
||||||
|
);
|
||||||
|
|
||||||
// Compile time assert that this priority is supported by the device
|
// Compile time assert that this priority is supported by the device
|
||||||
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
|
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
|
||||||
|
|
|
@ -4,13 +4,20 @@ use rtic_syntax::{analyze::Ownership, ast::App};
|
||||||
|
|
||||||
use crate::{analyze::Analysis, check::Extra, codegen::util};
|
use crate::{analyze::Analysis, check::Extra, codegen::util};
|
||||||
|
|
||||||
/// Generates `static [mut]` variables and resource proxies
|
/// Generates `static` variables and resource proxies
|
||||||
|
/// Early resources are stored in `RacyCell<T>`
|
||||||
|
/// Late resource are stored in `RacyCell<MaybeUninit<T>>`
|
||||||
|
///
|
||||||
|
/// Safety:
|
||||||
|
/// - RacyCell<T> access is `unsafe`.
|
||||||
|
/// - RacyCell<MaybeUninit> is always written to before user access, thus
|
||||||
|
// the generated code for user access can safely `assume_init`.
|
||||||
pub fn codegen(
|
pub fn codegen(
|
||||||
app: &App,
|
app: &App,
|
||||||
analysis: &Analysis,
|
analysis: &Analysis,
|
||||||
extra: &Extra,
|
extra: &Extra,
|
||||||
) -> (
|
) -> (
|
||||||
// mod_app -- the `static [mut]` variables behind the proxies
|
// mod_app -- the `static` variables behind the proxies
|
||||||
Vec<TokenStream2>,
|
Vec<TokenStream2>,
|
||||||
// mod_resources -- the `resources` module
|
// mod_resources -- the `resources` module
|
||||||
TokenStream2,
|
TokenStream2,
|
||||||
|
@ -24,35 +31,51 @@ pub fn codegen(
|
||||||
let mangled_name = util::mark_internal_ident(&name);
|
let mangled_name = util::mark_internal_ident(&name);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// late resources in `util::link_section_uninit`
|
||||||
let section = if expr.is_none() {
|
let section = if expr.is_none() {
|
||||||
util::link_section_uninit(true)
|
util::link_section_uninit(true)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// resource type and assigned value
|
||||||
let (ty, expr) = if let Some(expr) = expr {
|
let (ty, expr) = if let Some(expr) = expr {
|
||||||
(quote!(#ty), quote!(#expr))
|
// early resource
|
||||||
} else {
|
|
||||||
(
|
(
|
||||||
quote!(core::mem::MaybeUninit<#ty>),
|
quote!(rtic::RacyCell<#ty>),
|
||||||
quote!(core::mem::MaybeUninit::uninit()),
|
quote!(rtic::RacyCell::new(#expr)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// late resource
|
||||||
|
(
|
||||||
|
quote!(rtic::RacyCell<core::mem::MaybeUninit<#ty>>),
|
||||||
|
quote!(rtic::RacyCell::new(core::mem::MaybeUninit::uninit())),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let attrs = &res.attrs;
|
let attrs = &res.attrs;
|
||||||
|
|
||||||
|
// For future use
|
||||||
|
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
|
||||||
mod_app.push(quote!(
|
mod_app.push(quote!(
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
|
// #[doc = #doc]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#section
|
#section
|
||||||
static mut #mangled_name: #ty = #expr;
|
static #mangled_name: #ty = #expr;
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let r_prop = &res.properties;
|
let r_prop = &res.properties;
|
||||||
|
// For future use
|
||||||
|
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
|
||||||
|
|
||||||
if !r_prop.task_local && !r_prop.lock_free {
|
if !r_prop.task_local && !r_prop.lock_free {
|
||||||
mod_resources.push(quote!(
|
mod_resources.push(quote!(
|
||||||
|
// #[doc = #doc]
|
||||||
|
#[doc(hidden)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
pub struct #name<'a> {
|
pub struct #name<'a> {
|
||||||
|
@ -73,15 +96,23 @@ pub fn codegen(
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
let ptr = if expr.is_none() {
|
let (ptr, _doc) = if expr.is_none() {
|
||||||
quote!(
|
// late resource
|
||||||
#(#cfgs)*
|
(
|
||||||
#mangled_name.as_mut_ptr()
|
quote!(
|
||||||
|
#(#cfgs)*
|
||||||
|
#mangled_name.get_mut_unchecked().as_mut_ptr()
|
||||||
|
),
|
||||||
|
"late",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
quote!(
|
// early resource
|
||||||
#(#cfgs)*
|
(
|
||||||
&mut #mangled_name
|
quote!(
|
||||||
|
#(#cfgs)*
|
||||||
|
#mangled_name.get_mut_unchecked()
|
||||||
|
),
|
||||||
|
"early",
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,6 +123,9 @@ pub fn codegen(
|
||||||
None => 0,
|
None => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For future use
|
||||||
|
// let doc = format!(" RTIC internal ({} resource): {}:{}", doc, file!(), line!());
|
||||||
|
|
||||||
mod_app.push(util::impl_mutex(
|
mod_app.push(util::impl_mutex(
|
||||||
extra,
|
extra,
|
||||||
cfgs,
|
cfgs,
|
||||||
|
|
|
@ -79,9 +79,9 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
|
||||||
let is_late = expr.is_none();
|
let is_late = expr.is_none();
|
||||||
if is_late {
|
if is_late {
|
||||||
let expr = if access.is_exclusive() {
|
let expr = if access.is_exclusive() {
|
||||||
quote!(&mut *#mangled_name.as_mut_ptr())
|
quote!(&mut *#mangled_name.get_mut_unchecked().as_mut_ptr())
|
||||||
} else {
|
} else {
|
||||||
quote!(&*#mangled_name.as_ptr())
|
quote!(&*#mangled_name.get_unchecked().as_ptr())
|
||||||
};
|
};
|
||||||
|
|
||||||
values.push(quote!(
|
values.push(quote!(
|
||||||
|
@ -91,7 +91,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
|
||||||
} else {
|
} else {
|
||||||
values.push(quote!(
|
values.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#name: &#mut_ #mangled_name
|
#name: #mangled_name.get_mut_unchecked()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ pub fn codegen(
|
||||||
// /// Queue version of a free-list that keeps track of empty slots in
|
// /// Queue version of a free-list that keeps track of empty slots in
|
||||||
// /// the following buffers
|
// /// the following buffers
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
static mut #fq: #fq_ty = #fq_expr;
|
static #fq: rtic::RacyCell<#fq_ty> = rtic::RacyCell::new(#fq_expr);
|
||||||
));
|
));
|
||||||
|
|
||||||
let elems = &(0..cap)
|
let elems = &(0..cap)
|
||||||
|
@ -65,13 +65,16 @@ pub fn codegen(
|
||||||
let mono_type = &monotonic.ty;
|
let mono_type = &monotonic.ty;
|
||||||
|
|
||||||
let uninit = mk_uninit();
|
let uninit = mk_uninit();
|
||||||
|
// For future use
|
||||||
|
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
|
||||||
mod_app.push(quote!(
|
mod_app.push(quote!(
|
||||||
#uninit
|
#uninit
|
||||||
// /// Buffer that holds the instants associated to the inputs of a task
|
// /// Buffer that holds the instants associated to the inputs of a task
|
||||||
|
// #[doc = #doc]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
static mut #instants:
|
static #instants:
|
||||||
[core::mem::MaybeUninit<rtic::time::Instant<#mono_type>>; #cap_lit] =
|
rtic::RacyCell<[core::mem::MaybeUninit<rtic::time::Instant<#mono_type>>; #cap_lit]> =
|
||||||
[#(#elems,)*];
|
rtic::RacyCell::new([#(#elems,)*]);
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,8 +85,8 @@ pub fn codegen(
|
||||||
#uninit
|
#uninit
|
||||||
// /// Buffer that holds the inputs of a task
|
// /// Buffer that holds the inputs of a task
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
static mut #inputs_ident: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
|
static #inputs_ident: rtic::RacyCell<[core::mem::MaybeUninit<#input_ty>; #cap_lit]> =
|
||||||
[#(#elems,)*];
|
rtic::RacyCell::new([#(#elems,)*]);
|
||||||
));
|
));
|
||||||
|
|
||||||
// `${task}Resources`
|
// `${task}Resources`
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
// #[doc = #doc]
|
// #[doc = #doc]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
static mut #tq_marker: u32 = 0;
|
static #tq_marker: rtic::RacyCell<u32> = rtic::RacyCell::new(0);
|
||||||
));
|
));
|
||||||
|
|
||||||
let t = util::schedule_t_ident();
|
let t = util::schedule_t_ident();
|
||||||
|
@ -35,6 +35,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// For future use
|
||||||
// let doc = "Tasks that can be scheduled".to_string();
|
// let doc = "Tasks that can be scheduled".to_string();
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
// #[doc = #doc]
|
// #[doc = #doc]
|
||||||
|
@ -61,6 +62,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
|
|
||||||
// Static variables and resource proxy
|
// Static variables and resource proxy
|
||||||
{
|
{
|
||||||
|
// For future use
|
||||||
// let doc = &format!("Timer queue for {}", monotonic_name);
|
// let doc = &format!("Timer queue for {}", monotonic_name);
|
||||||
let cap = app
|
let cap = app
|
||||||
.software_tasks
|
.software_tasks
|
||||||
|
@ -71,18 +73,22 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
let tq_ty =
|
let tq_ty =
|
||||||
quote!(core::mem::MaybeUninit<rtic::export::TimerQueue<#mono_type, #t, #n>>);
|
quote!(core::mem::MaybeUninit<rtic::export::TimerQueue<#mono_type, #t, #n>>);
|
||||||
|
|
||||||
|
// For future use
|
||||||
|
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
static mut #tq: #tq_ty = core::mem::MaybeUninit::uninit();
|
static #tq: rtic::RacyCell<#tq_ty> =
|
||||||
|
rtic::RacyCell::new(core::mem::MaybeUninit::uninit());
|
||||||
));
|
));
|
||||||
|
|
||||||
let mono = util::monotonic_ident(&monotonic_name);
|
let mono = util::monotonic_ident(&monotonic_name);
|
||||||
let mono = util::mark_internal_ident(&mono);
|
let mono = util::mark_internal_ident(&mono);
|
||||||
|
// For future use
|
||||||
// let doc = &format!("Storage for {}", monotonic_name);
|
// let doc = &format!("Storage for {}", monotonic_name);
|
||||||
|
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
static mut #mono: Option<#mono_type> = None;
|
static #mono: rtic::RacyCell<Option<#mono_type>> = rtic::RacyCell::new(None);
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +119,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
quote!(
|
quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#t::#name => {
|
#t::#name => {
|
||||||
rtic::export::interrupt::free(|_| #rq.split().0.enqueue_unchecked((#rqt::#name, index)));
|
rtic::export::interrupt::free(|_| #rq.get_mut_unchecked().split().0.enqueue_unchecked((#rqt::#name, index)));
|
||||||
|
|
||||||
#pend
|
#pend
|
||||||
}
|
}
|
||||||
|
@ -132,10 +138,9 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
unsafe fn #bound_interrupt() {
|
unsafe fn #bound_interrupt() {
|
||||||
|
|
||||||
while let Some((task, index)) = rtic::export::interrupt::free(|_|
|
while let Some((task, index)) = rtic::export::interrupt::free(|_|
|
||||||
if let Some(mono) = #app_path::#m_ident.as_mut() {
|
if let Some(mono) = #app_path::#m_ident.get_mut_unchecked().as_mut() {
|
||||||
(&mut *#tq.as_mut_ptr()).dequeue(|| #disable_isr, mono)
|
(&mut *#tq.get_mut_unchecked().as_mut_ptr()).dequeue(|| #disable_isr, mono)
|
||||||
} else {
|
} else {
|
||||||
// We can only use the timer queue if `init` has returned, and it
|
// We can only use the timer queue if `init` has returned, and it
|
||||||
// writes the `Some(monotonic)` we are accessing here.
|
// writes the `Some(monotonic)` we are accessing here.
|
||||||
|
@ -147,7 +152,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rtic::export::interrupt::free(|_| if let Some(mono) = #app_path::#m_ident.as_mut() {
|
rtic::export::interrupt::free(|_| if let Some(mono) = #app_path::#m_ident.get_mut_unchecked().as_mut() {
|
||||||
mono.on_interrupt();
|
mono.on_interrupt();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
28
src/lib.rs
28
src/lib.rs
|
@ -57,3 +57,31 @@ where
|
||||||
{
|
{
|
||||||
NVIC::pend(interrupt)
|
NVIC::pend(interrupt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
|
/// Internal replacement for `static mut T`
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct RacyCell<T>(UnsafeCell<T>);
|
||||||
|
|
||||||
|
impl<T> RacyCell<T> {
|
||||||
|
/// Create a RacyCell
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn new(value: T) -> Self {
|
||||||
|
RacyCell(UnsafeCell::new(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get `&mut T`
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn get_mut_unchecked(&self) -> &mut T {
|
||||||
|
&mut *self.0.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get `&T`
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn get_unchecked(&self) -> &T {
|
||||||
|
&*self.0.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> Sync for RacyCell<T> {}
|
||||||
|
|
Loading…
Reference in a new issue