diff --git a/examples/lockall.rs b/examples/lockall.rs new file mode 100644 index 0000000000..5a00ad858f --- /dev/null +++ b/examples/lockall.rs @@ -0,0 +1,73 @@ +//! examples/lock.rs + +// #![deny(unsafe_code)] +// #![deny(warnings)] +#![no_main] +#![no_std] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + a: u32, + b: i64, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local, init::Monotonics) { + foo::spawn().unwrap(); + + (Shared { a: 1, b: 2 }, Local {}, init::Monotonics()) + } + + // when omitted priority is assumed to be `1` + #[task(shared = [a, b])] + fn foo(mut c: foo::Context) { + static mut X: Option<&'static mut u32> = None; + static mut Y: u32 = 0; + let _ = hprintln!("before lock"); + c.shared.lock(|s| { + let _ = hprintln!("in lock"); + let _ = hprintln!("here {}, {}", s.a, s.b); + *s.a += 1; + + // soundness check + // c.shared.lock(|s| {}); // borrow error + // c.shared.a.lock(|s| {}); // borrow error + + unsafe { + X = Some(&mut Y); + // X = Some(s.a); // lifetime issue + // X = Some(&mut *s.a); // lifetime issue + // X = Some(&'static mut *s.a); // not rust + } + let _ = hprintln!("here {}, {}", s.a, s.b); + }); + // the lower priority task requires a critical section to access the data + // c.shared.shared.lock(|shared| { + // // data can only be modified within this critical section (closure) + // *shared += 1; + + // // bar will *not* run right now due to the critical section + // bar::spawn().unwrap(); + + // hprintln!("B - shared = {}", *shared).unwrap(); + + // // baz does not contend for `shared` so it's allowed to run now + // baz::spawn().unwrap(); + // }); + + // // critical section is over: bar can now start + + // hprintln!("E").unwrap(); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/macros/src/codegen/shared_resources.rs b/macros/src/codegen/shared_resources.rs index a115b7c20a..c53143d735 100644 --- a/macros/src/codegen/shared_resources.rs +++ b/macros/src/codegen/shared_resources.rs @@ -106,5 +106,62 @@ pub fn codegen( }) }; + let manual = "Manual Codegen".to_string(); + + let to_gen = quote! { + + pub struct __rtic_internal_fooShared { + a: &'static mut u32, + b: &'static mut i64, + } + + + impl __rtic_internal_fooShared { + #[inline(always)] + pub unsafe fn new() -> Self { + __rtic_internal_fooShared { + a: &mut *__rtic_internal_shared_resource_a + .get_mut_unchecked() + .as_mut_ptr(), + b: &mut *__rtic_internal_shared_resource_b + .get_mut_unchecked() + .as_mut_ptr(), + } + } + } + + #[doc = #manual] + impl<'a> __rtic_internal_fooSharedResources<'a> { + #[inline(always)] + pub unsafe fn priority(&self) -> &rtic::export::Priority { + self.priority + } + } + + #[doc = #manual] + impl<'a> rtic::Mutex for __rtic_internal_fooSharedResources<'a> { + type T = __rtic_internal_fooShared; + #[inline(always)] + fn lock( + &mut self, + f: impl FnOnce(&mut __rtic_internal_fooShared) -> RTIC_INTERNAL_R, + ) -> RTIC_INTERNAL_R { + /// Priority ceiling + const CEILING: u8 = 1u8; + unsafe { + rtic::export::lock( + &mut __rtic_internal_fooShared::new(), + self.priority(), + CEILING, + lm3s6965::NVIC_PRIO_BITS, + f, + ) + } + } + } + }; + + mod_app.push(to_gen); + (mod_app, mod_resources) } diff --git a/macros/src/codegen/shared_resources_struct.rs b/macros/src/codegen/shared_resources_struct.rs index 7ae8d8086e..dd583291e8 100644 --- a/macros/src/codegen/shared_resources_struct.rs +++ b/macros/src/codegen/shared_resources_struct.rs @@ -109,6 +109,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2, #[doc = #doc] pub struct #ident<#lt> { #(#fields,)* + priority: &'a rtic::export::Priority, } ); @@ -123,6 +124,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2, pub unsafe fn new(#arg) -> Self { #ident { #(#values,)* + priority } } }