diff --git a/examples/lockall_cost.rs b/examples/lockall_cost.rs index ba87e8e488..a0cd520196 100644 --- a/examples/lockall_cost.rs +++ b/examples/lockall_cost.rs @@ -29,10 +29,10 @@ mod app { cx.shared.lock(|x| *x.shared += 1); } - #[task(binds = GPIOB, priority = 2, shared = [shared])] - fn high(mut cx: high::Context) { - cx.shared.lock(|x| *x.shared += 1); - } + // #[task(binds = GPIOB, priority = 2, shared = [shared])] + // fn high(mut cx: high::Context) { + // cx.shared.lock(|x| *x.shared += 1); + // } } // cargo objdump --example lockall_cost --target thumbv7m-none-eabi --release --features inline-asm -- --disassemble > lockall_cost.ojbdump diff --git a/macros/src/codegen/hardware_tasks.rs b/macros/src/codegen/hardware_tasks.rs index 8532176e50..da0d6441c5 100644 --- a/macros/src/codegen/hardware_tasks.rs +++ b/macros/src/codegen/hardware_tasks.rs @@ -99,6 +99,7 @@ pub fn codegen( #[allow(non_snake_case)] fn #name(#context: #name::Context) { use rtic::Mutex as _; + use rtic::MutexStruct as _; use rtic::mutex_prelude::*; #(#stmts)* diff --git a/macros/src/codegen/idle.rs b/macros/src/codegen/idle.rs index 09a955988c..718ed2617e 100644 --- a/macros/src/codegen/idle.rs +++ b/macros/src/codegen/idle.rs @@ -73,6 +73,7 @@ pub fn codegen( #[allow(non_snake_case)] fn #name(#context: #name::Context) -> ! { use rtic::Mutex as _; + use rtic::MutexStruct as _; use rtic::mutex_prelude::*; #(#stmts)* diff --git a/macros/src/codegen/shared_resources_struct.rs b/macros/src/codegen/shared_resources_struct.rs index 21a1f99161..6ca9710bd6 100644 --- a/macros/src/codegen/shared_resources_struct.rs +++ b/macros/src/codegen/shared_resources_struct.rs @@ -168,14 +168,14 @@ pub fn codegen( let (lock_all, get_prio) = if let Some(name) = field_get_prio { ( - util::impl_mutex( + util::impl_mutex_struct( extra, &vec![], // TODO: what cfg should go here? quote!(#ident), quote!(#ident_mut<#lt>), max_ceiling, quote!(self.priority()), - quote!(|| { &mut #ident_mut::new() }), + quote!(|| { #ident_mut::new() }), ), quote!( // Used by the lock-all API diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs index c8ea305954..56779c7b61 100644 --- a/macros/src/codegen/software_tasks.rs +++ b/macros/src/codegen/software_tasks.rs @@ -132,6 +132,7 @@ pub fn codegen( #[allow(non_snake_case)] fn #name(#context: #name::Context #(,#inputs)*) { use rtic::Mutex as _; + use rtic::MutexStruct as _; use rtic::mutex_prelude::*; #(#stmts)* diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs index 9f84359c05..671f839a04 100644 --- a/macros/src/codegen/util.rs +++ b/macros/src/codegen/util.rs @@ -54,6 +54,41 @@ pub fn impl_mutex( ) } +/// Generates a `MutexStruct` implementation +pub fn impl_mutex_struct( + extra: &Extra, + cfgs: &[Attribute], + path: TokenStream2, + ty: TokenStream2, + ceiling: u8, + priority: TokenStream2, + ptr: TokenStream2, +) -> TokenStream2 { + let device = &extra.device; + quote!( + #(#cfgs)* + impl<'a> rtic::MutexStruct for #path<'a> { + type T = #ty; + + #[inline(always)] + fn lock(&mut self, f: impl FnOnce(#ty) -> RTIC_INTERNAL_R) -> RTIC_INTERNAL_R { + /// Priority ceiling + const CEILING: u8 = #ceiling; + + unsafe { + rtic::export::lock_struct( + #ptr, + #priority, + CEILING, + #device::NVIC_PRIO_BITS, + f, + ) + } + } + } + ) +} + /// Generates an identifier for the `INPUTS` buffer (`spawn` & `schedule` API) pub fn inputs_ident(task: &Ident) -> Ident { mark_internal_name(&format!("{}_INPUTS", task)) diff --git a/src/export.rs b/src/export.rs index 74b1d2ffc2..c10b340ebc 100644 --- a/src/export.rs +++ b/src/export.rs @@ -161,6 +161,43 @@ pub unsafe fn lock( } } +/// Lock the resource proxy by setting the BASEPRI +/// and running the closure with interrupt::free +/// +/// # Safety +/// +/// Writing to the BASEPRI +/// Dereferencing a raw pointer +#[cfg(armv7m)] +#[inline(always)] +pub unsafe fn lock_struct( + ptr: impl Fn() -> T, + priority: &Priority, + ceiling: u8, + nvic_prio_bits: u8, + f: impl FnOnce(T) -> R, +) -> R { + let current = priority.get(); + + if current < ceiling { + if ceiling == (1 << nvic_prio_bits) { + priority.set(u8::max_value()); + let r = interrupt::free(|_| f(ptr())); + priority.set(current); + r + } else { + priority.set(ceiling); + basepri::write(logical2hw(ceiling, nvic_prio_bits)); + let r = f(ptr()); // inside of lock + basepri::write(logical2hw(current, nvic_prio_bits)); + priority.set(current); + r + } + } else { + f(ptr()) + } +} + /// Lock the resource proxy by setting the PRIMASK /// and running the closure with interrupt::free /// diff --git a/src/lib.rs b/src/lib.rs index 8463442acf..a78114b165 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,3 +104,12 @@ impl RacyCell { } unsafe impl Sync for RacyCell {} + +/// Should be moved to `rtic-core` +pub trait MutexStruct { + /// Data protected by the mutex + type T; + + /// Creates a critical section and grants temporary access to the protected data + fn lock(&mut self, f: impl FnOnce(Self::T) -> R) -> R; +}