From 6aa0fb450f417ce899b43f4539eb226b391a0f2e Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 8 Apr 2021 18:25:09 +0200 Subject: [PATCH 1/2] Goodbye static mut --- macros/src/codegen.rs | 2 +- macros/src/codegen/dispatchers.rs | 12 ++++-- macros/src/codegen/locals.rs | 6 +-- macros/src/codegen/module.rs | 38 ++++++++++------ macros/src/codegen/post_init.rs | 15 +++++-- macros/src/codegen/pre_init.rs | 6 ++- macros/src/codegen/resources.rs | 60 ++++++++++++++++++++------ macros/src/codegen/resources_struct.rs | 6 +-- macros/src/codegen/software_tasks.rs | 14 +++--- macros/src/codegen/timer_queue.rs | 17 ++++---- src/lib.rs | 28 ++++++++++++ 11 files changed, 145 insertions(+), 59 deletions(-) diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index cf728a7d3f..167ba500a6 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -125,7 +125,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 { rtic::export::interrupt::free(|_| { use rtic::Monotonic 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() { v } else { diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs index dc33b1af60..6aca901aea 100644 --- a/macros/src/codegen/dispatchers.rs +++ b/macros/src/codegen/dispatchers.rs @@ -59,7 +59,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec = rtic::RacyCell::new(#rq_expr); )); let arms = channel @@ -86,8 +86,12 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec { let #tupled = - #inputs.get_unchecked(usize::from(index)).as_ptr().read(); - #fq.split().0.enqueue_unchecked(index); + #inputs + .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); #app_path::#name( #locals_new @@ -100,7 +104,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec>(); 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 { #(#arms)* } diff --git a/macros/src/codegen/locals.rs b/macros/src/codegen/locals.rs index 5725a1513f..0fb8c6d298 100644 --- a/macros/src/codegen/locals.rs +++ b/macros/src/codegen/locals.rs @@ -50,11 +50,11 @@ pub fn codegen( items.push(quote!( #(#cfgs)* #[doc(hidden)] - static mut #name: #ty = #expr + static #name: rtic::RacyCell<#ty> = rtic::RacyCell::new(#expr) )); values.push(quote!( #(#cfgs)* - #name: &mut #name + #name: #name.get_mut_unchecked() )); names.push(name); pats.push(quote!( @@ -64,7 +64,7 @@ pub fn codegen( } 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)); } diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs index 50146c0214..8c148ccb14 100644 --- a/macros/src/codegen/module.rs +++ b/macros/src/codegen/module.rs @@ -245,14 +245,15 @@ pub fn codegen( let input = #tupled; 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 + .get_mut_unchecked() .get_unchecked_mut(usize::from(index)) .as_mut_ptr() .write(input); 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); @@ -304,6 +305,9 @@ pub fn codegen( let user_imports = &app.user_imports; let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident()); + // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); + // items.push(quote!(#[doc = #doc])); + items.push(quote!( /// Holds methods related to this monotonic pub mod #m { @@ -325,12 +329,16 @@ pub fn codegen( impl SpawnHandle { pub fn cancel(self) -> Result<#ty, ()> { 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) { // 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 - #app_path::#fq.split().0.enqueue_unchecked(index); + #app_path::#fq.get_mut_unchecked().split().0.enqueue_unchecked(index); Ok(msg) } else { @@ -350,10 +358,10 @@ pub fn codegen( pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result { rtic::export::interrupt::free(|_| unsafe { - let marker = #tq_marker; - #tq_marker = #tq_marker.wrapping_add(1); + let marker = *#tq_marker.get_mut_unchecked(); + *#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 }) }) @@ -373,7 +381,7 @@ pub fn codegen( 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) } else { #app_path::monotonics::#m::now() @@ -390,19 +398,21 @@ pub fn codegen( ) -> Result { unsafe { 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 + .get_mut_unchecked() .get_unchecked_mut(usize::from(index)) .as_mut_ptr() .write(input); #app_path::#instants + .get_mut_unchecked() .get_unchecked_mut(usize::from(index)) .as_mut_ptr() .write(instant); rtic::export::interrupt::free(|_| { - let marker = #tq_marker; + let marker = *#tq_marker.get_mut_unchecked(); let nr = rtic::export::NotReady { instant, index, @@ -410,15 +420,15 @@ pub fn codegen( 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( nr, || #enable_interrupt, || #pend, - #app_path::#m_ident.as_mut()); + #app_path::#m_ident.get_mut_unchecked().as_mut()); Ok(SpawnHandle { marker }) }) diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs index 96c5df80f9..7dd1590338 100644 --- a/macros/src/codegen/post_init.rs +++ b/macros/src/codegen/post_init.rs @@ -17,16 +17,23 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec { // 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> + // - `get_mut_unchecked` to obtain `MaybeUninit` + // - `as_mut_ptr` to obtain a raw pointer to `MaybeUninit` + // - `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() { + // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); + // stmts.push(quote!(#[doc = #doc])); + let idx = Index { index: i as u32, span: Span::call_site(), @@ -36,7 +43,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec { // Store the monotonic let name = util::monotonic_ident(&monotonic.to_string()); 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 diff --git a/macros/src/codegen/pre_init.rs b/macros/src/codegen/pre_init.rs index 287f41a43e..3a62da504e 100644 --- a/macros/src/codegen/pre_init.rs +++ b/macros/src/codegen/pre_init.rs @@ -20,7 +20,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec Vec` +/// Late resource are stored in `RacyCell>` +/// +/// Safety: +/// - RacyCell access is `unsafe`. +/// - RacyCell 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, // mod_resources -- the `resources` module TokenStream2, @@ -24,35 +31,50 @@ 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)) - } else { + // early resource ( - quote!(core::mem::MaybeUninit<#ty>), - quote!(core::mem::MaybeUninit::uninit()), + quote!(rtic::RacyCell<#ty>), + quote!(rtic::RacyCell::new(#expr)), + ) + } else { + // late resource + ( + quote!(rtic::RacyCell>), + quote!(rtic::RacyCell::new(core::mem::MaybeUninit::uninit())), ) }; let attrs = &res.attrs; + + // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); mod_app.push(quote!( #[allow(non_upper_case_globals)] + // #[doc = #doc] #[doc(hidden)] #(#attrs)* #(#cfgs)* #section - static mut #mangled_name: #ty = #expr; + static #mangled_name: #ty = #expr; )); } let r_prop = &res.properties; + // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); + if !r_prop.task_local && !r_prop.lock_free { mod_resources.push(quote!( + // #[doc = #doc] + #[doc(hidden)] #[allow(non_camel_case_types)] #(#cfgs)* pub struct #name<'a> { @@ -73,15 +95,23 @@ pub fn codegen( } )); - let ptr = if expr.is_none() { - quote!( - #(#cfgs)* - #mangled_name.as_mut_ptr() + let (ptr, _doc) = if expr.is_none() { + // late resource + ( + quote!( + #(#cfgs)* + #mangled_name.get_mut_unchecked().as_mut_ptr() + ), + "late", ) } else { - quote!( - #(#cfgs)* - &mut #mangled_name + // early resource + ( + quote!( + #(#cfgs)* + #mangled_name.get_mut_unchecked() + ), + "early", ) }; @@ -92,6 +122,8 @@ pub fn codegen( None => 0, }; + // let doc = format!(" RTIC internal ({} resource): {}:{}", doc, file!(), line!()); + mod_app.push(util::impl_mutex( extra, cfgs, diff --git a/macros/src/codegen/resources_struct.rs b/macros/src/codegen/resources_struct.rs index 8ed8a2912c..6fe4678a62 100644 --- a/macros/src/codegen/resources_struct.rs +++ b/macros/src/codegen/resources_struct.rs @@ -79,9 +79,9 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2, let is_late = expr.is_none(); if is_late { let expr = if access.is_exclusive() { - quote!(&mut *#mangled_name.as_mut_ptr()) + quote!(&mut *#mangled_name.get_mut_unchecked().as_mut_ptr()) } else { - quote!(&*#mangled_name.as_ptr()) + quote!(&*#mangled_name.get_unchecked().as_ptr()) }; values.push(quote!( @@ -91,7 +91,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2, } else { values.push(quote!( #(#cfgs)* - #name: &#mut_ #mangled_name + #name: #mangled_name.get_mut_unchecked() )); } } diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs index a39fe4cc2e..e42fb88d41 100644 --- a/macros/src/codegen/software_tasks.rs +++ b/macros/src/codegen/software_tasks.rs @@ -52,7 +52,7 @@ pub fn codegen( // /// Queue version of a free-list that keeps track of empty slots in // /// the following buffers #[doc(hidden)] - static mut #fq: #fq_ty = #fq_expr; + static #fq: rtic::RacyCell<#fq_ty> = rtic::RacyCell::new(#fq_expr); )); let elems = &(0..cap) @@ -65,13 +65,15 @@ pub fn codegen( let mono_type = &monotonic.ty; let uninit = mk_uninit(); + // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); mod_app.push(quote!( #uninit // /// Buffer that holds the instants associated to the inputs of a task + // #[doc = #doc] #[doc(hidden)] - static mut #instants: - [core::mem::MaybeUninit>; #cap_lit] = - [#(#elems,)*]; + static #instants: + rtic::RacyCell<[core::mem::MaybeUninit>; #cap_lit]> = + rtic::RacyCell::new([#(#elems,)*]); )); } @@ -82,8 +84,8 @@ pub fn codegen( #uninit // /// Buffer that holds the inputs of a task #[doc(hidden)] - static mut #inputs_ident: [core::mem::MaybeUninit<#input_ty>; #cap_lit] = - [#(#elems,)*]; + static #inputs_ident: rtic::RacyCell<[core::mem::MaybeUninit<#input_ty>; #cap_lit]> = + rtic::RacyCell::new([#(#elems,)*]); )); // `${task}Resources` diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs index 0d2c51ead9..ed89af660e 100644 --- a/macros/src/codegen/timer_queue.rs +++ b/macros/src/codegen/timer_queue.rs @@ -15,7 +15,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec = rtic::RacyCell::new(0); )); let t = util::schedule_t_ident(); @@ -71,9 +71,11 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec>); + // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); items.push(quote!( #[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); @@ -82,7 +84,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec = None; + static #mono: rtic::RacyCell> = rtic::RacyCell::new(None); )); } @@ -113,7 +115,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec { - 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 } @@ -132,10 +134,9 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec Vec(UnsafeCell); + +impl RacyCell { + /// 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 Sync for RacyCell {} From 50f26e78eda57cb1f9f815aa93b357c2cd1a0205 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 22 Apr 2021 18:38:42 +0200 Subject: [PATCH 2/2] Keep comments --- macros/src/codegen/dispatchers.rs | 2 ++ macros/src/codegen/module.rs | 1 + macros/src/codegen/post_init.rs | 1 + macros/src/codegen/resources.rs | 4 +++- macros/src/codegen/software_tasks.rs | 1 + macros/src/codegen/timer_queue.rs | 4 ++++ 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs index 6aca901aea..382e33fe40 100644 --- a/macros/src/codegen/dispatchers.rs +++ b/macros/src/codegen/dispatchers.rs @@ -26,6 +26,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec>(); + // For future use // let doc = format!( // "Software tasks to be dispatched at priority level {}", // level, @@ -53,6 +54,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec Vec { } for (i, (monotonic, _)) in app.monotonics.iter().enumerate() { + // For future use // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); // stmts.push(quote!(#[doc = #doc])); diff --git a/macros/src/codegen/resources.rs b/macros/src/codegen/resources.rs index 5352369685..a623ea6037 100644 --- a/macros/src/codegen/resources.rs +++ b/macros/src/codegen/resources.rs @@ -31,7 +31,6 @@ 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) @@ -56,6 +55,7 @@ pub fn codegen( let attrs = &res.attrs; + // For future use // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); mod_app.push(quote!( #[allow(non_upper_case_globals)] @@ -69,6 +69,7 @@ pub fn codegen( } let r_prop = &res.properties; + // For future use // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); if !r_prop.task_local && !r_prop.lock_free { @@ -122,6 +123,7 @@ pub fn codegen( None => 0, }; + // For future use // let doc = format!(" RTIC internal ({} resource): {}:{}", doc, file!(), line!()); mod_app.push(util::impl_mutex( diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs index e42fb88d41..0372e8ec83 100644 --- a/macros/src/codegen/software_tasks.rs +++ b/macros/src/codegen/software_tasks.rs @@ -65,6 +65,7 @@ pub fn codegen( let mono_type = &monotonic.ty; let uninit = mk_uninit(); + // For future use // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); mod_app.push(quote!( #uninit diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs index ed89af660e..14e9105453 100644 --- a/macros/src/codegen/timer_queue.rs +++ b/macros/src/codegen/timer_queue.rs @@ -35,6 +35,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec>(); + // For future use // let doc = "Tasks that can be scheduled".to_string(); items.push(quote!( // #[doc = #doc] @@ -61,6 +62,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec Vec>); + // For future use // let doc = format!(" RTIC internal: {}:{}", file!(), line!()); items.push(quote!( #[doc(hidden)] @@ -80,6 +83,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec