aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Per Lindgren <per.lindgren@ltu.se> 2021-03-10 15:37:11 +0100
committerGravatar Per Lindgren <per.lindgren@ltu.se> 2021-03-10 15:37:11 +0100
commitdb1574bf6b978bfac19efae6ad77fe01511492db (patch)
tree96b5d7892538b4f2cbf6de7c221ca4d78ac71faf
parent3c86d713a6f8fdb052de80380a17468090e42624 (diff)
downloadrtic-db1574bf6b978bfac19efae6ad77fe01511492db.tar.gz
rtic-db1574bf6b978bfac19efae6ad77fe01511492db.tar.zst
rtic-db1574bf6b978bfac19efae6ad77fe01511492db.zip
goodby static mut, welcome back to UnsafeCell
-rw-r--r--examples/minimal_early_resource.rs25
-rw-r--r--examples/minimal_late_resource.rs29
-rw-r--r--macros/src/codegen/post_init.rs10
-rw-r--r--macros/src/codegen/resources.rs33
-rw-r--r--src/lib.rs21
5 files changed, 107 insertions, 11 deletions
diff --git a/examples/minimal_early_resource.rs b/examples/minimal_early_resource.rs
new file mode 100644
index 00000000..f6b6a1a5
--- /dev/null
+++ b/examples/minimal_early_resource.rs
@@ -0,0 +1,25 @@
+//! examples/idle.rs
+
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![no_main]
+#![no_std]
+
+use panic_semihosting as _;
+
+#[rtic::app(device = lm3s6965)]
+mod app {
+
+ #[resources]
+ struct Resources {
+ #[init(0)]
+ resource_x: u32,
+ }
+
+ #[idle(resources = [resource_x])]
+ fn idle(_: idle::Context) -> ! {
+ loop {
+ cortex_m::asm::nop();
+ }
+ }
+}
diff --git a/examples/minimal_late_resource.rs b/examples/minimal_late_resource.rs
new file mode 100644
index 00000000..2419b8d7
--- /dev/null
+++ b/examples/minimal_late_resource.rs
@@ -0,0 +1,29 @@
+//! examples/minimal_late_resource.rs
+
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![no_main]
+#![no_std]
+
+use panic_semihosting as _;
+
+#[rtic::app(device = lm3s6965)]
+mod app {
+
+ #[resources]
+ struct Resources {
+ resource_x: u32,
+ }
+
+ #[init]
+ fn init(_: init::Context) -> (init::LateResources, init::Monotonics) {
+ (init::LateResources { resource_x: 0 }, init::Monotonics {})
+ }
+
+ #[idle(resources = [resource_x])]
+ fn idle(_: idle::Context) -> ! {
+ loop {
+ cortex_m::asm::nop();
+ }
+ }
+}
diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs
index 96c5df80..eec633ba 100644
--- a/macros/src/codegen/post_init.rs
+++ b/macros/src/codegen/post_init.rs
@@ -17,10 +17,14 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
// If it's live
let cfgs = app.late_resources[name].cfgs.clone();
if analysis.locations.get(name).is_some() {
- // Need to also include the cfgs
stmts.push(quote!(
- #(#cfgs)*
- #mangled_name.as_mut_ptr().write(late.#name);
+ // We include the cfgs
+ #(#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);
));
}
}
diff --git a/macros/src/codegen/resources.rs b/macros/src/codegen/resources.rs
index fa52b86d..89f70f84 100644
--- a/macros/src/codegen/resources.rs
+++ b/macros/src/codegen/resources.rs
@@ -4,13 +4,20 @@ use rtic_syntax::{analyze::Ownership, ast::App};
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(
app: &App,
analysis: &Analysis,
extra: &Extra,
) -> (
- // mod_app -- the `static [mut]` variables behind the proxies
+ // mod_app -- the `static` variables behind the proxies
Vec<TokenStream2>,
// mod_resources -- the `resources` module
TokenStream2,
@@ -24,18 +31,26 @@ pub fn codegen(
let mangled_name = util::mark_internal_ident(&name);
{
+ // TODO: do we really need this in the single core case
+ // late resources in `util::link_section_uninit`
let section = if expr.is_none() {
util::link_section_uninit(true)
} else {
None
};
+ // resource type and assigned value
let (ty, expr) = if let Some(expr) = expr {
- (quote!(#ty), quote!(#expr))
+ // early resource
+ (
+ quote!(rtic::RacyCell<#ty>),
+ quote!(rtic::RacyCell::new(#expr)),
+ )
} else {
+ // late resource
(
- quote!(core::mem::MaybeUninit<#ty>),
- quote!(core::mem::MaybeUninit::uninit()),
+ quote!(rtic::RacyCell<core::mem::MaybeUninit<#ty>>),
+ quote!(rtic::RacyCell::new(core::mem::MaybeUninit::uninit())),
)
};
@@ -46,7 +61,7 @@ pub fn codegen(
#(#attrs)*
#(#cfgs)*
#section
- static mut #mangled_name: #ty = #expr;
+ static #mangled_name: #ty = #expr;
));
}
@@ -74,14 +89,16 @@ pub fn codegen(
));
let ptr = if expr.is_none() {
+ // late resource
quote!(
#(#cfgs)*
- #mangled_name.as_mut_ptr()
+ &mut #mangled_name.get_mut_unchecked().assume_init()
)
} else {
+ // early resource
quote!(
#(#cfgs)*
- &mut #mangled_name
+ unsafe { #mangled_name.get_mut_unchecked() }
)
};
diff --git a/src/lib.rs b/src/lib.rs
index 82207399..2da2ec95 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -55,3 +55,24 @@ where
{
NVIC::pend(interrupt)
}
+
+use core::cell::UnsafeCell;
+
+/// Internal replacement for `static mut T`
+// TODO: Decide name and location.
+pub struct RacyCell<T>(UnsafeCell<T>);
+
+impl<T> RacyCell<T> {
+ /// Create a RacyCell
+ pub const fn new(value: T) -> Self {
+ RacyCell(UnsafeCell::new(value))
+ }
+
+ /// Get &mut T
+ pub unsafe fn get_mut_unchecked(&self) -> &mut T {
+ &mut *self.0.get()
+ }
+}
+
+// The type wrapped need to be Sync for RacyCell<T> to be Sync
+unsafe impl<T> Sync for RacyCell<T> where T: Sync {}