Removed Priority, simplified lifetime handling

This commit is contained in:
Emil Fresk 2023-01-07 11:24:13 +01:00 committed by Henrik Tjäder
parent 53f3d397e7
commit 714020a624
15 changed files with 99 additions and 236 deletions

View file

@ -15,7 +15,9 @@ mod app {
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
#[shared] #[shared]
struct Shared {} struct Shared {
a: u32,
}
#[local] #[local]
struct Local {} struct Local {}
@ -25,11 +27,12 @@ mod app {
hprintln!("init").unwrap(); hprintln!("init").unwrap();
async_task::spawn().unwrap(); async_task::spawn().unwrap();
async_task2::spawn().unwrap();
(Shared {}, Local {}) (Shared { a: 0 }, Local {})
} }
#[idle] #[idle(shared = [a])]
fn idle(_: idle::Context) -> ! { fn idle(_: idle::Context) -> ! {
// debug::exit(debug::EXIT_SUCCESS); // debug::exit(debug::EXIT_SUCCESS);
loop { loop {
@ -38,10 +41,23 @@ mod app {
} }
} }
#[task] #[task(binds = UART1, shared = [a])]
async fn async_task(_cx: async_task::Context) { fn hw_task(cx: hw_task::Context) {
let hw_task::SharedResources { a } = cx.shared;
hprintln!("hello from hw").ok();
}
#[task(shared = [a])]
async fn async_task(cx: async_task::Context) {
let async_task::SharedResources { a } = cx.shared;
hprintln!("hello from async").ok(); hprintln!("hello from async").ok();
debug::exit(debug::EXIT_SUCCESS); debug::exit(debug::EXIT_SUCCESS);
} }
#[task(priority = 2, shared = [a])]
async fn async_task2(cx: async_task2::Context) {
let async_task2::SharedResources { a } = cx.shared;
hprintln!("hello from async2").ok();
}
} }

View file

@ -0,0 +1 @@

View file

@ -19,6 +19,10 @@ mod shared_resources_struct;
mod software_tasks; mod software_tasks;
mod util; mod util;
// TODO: organize codegen to actual parts of code
// so `main::codegen` generates ALL the code for `fn main`,
// `software_tasks::codegen` generates ALL the code for software tasks etc...
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub fn app(app: &App, analysis: &Analysis) -> TokenStream2 { pub fn app(app: &App, analysis: &Analysis) -> TokenStream2 {
let mut mod_app = vec![]; let mut mod_app = vec![];

View file

@ -13,7 +13,6 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
for (name, _) in app.software_tasks.iter() { for (name, _) in app.software_tasks.iter() {
let type_name = util::internal_task_ident(name, "F"); let type_name = util::internal_task_ident(name, "F");
let exec_name = util::internal_task_ident(name, "EXEC"); let exec_name = util::internal_task_ident(name, "EXEC");
let prio_name = util::internal_task_ident(name, "PRIORITY");
items.push(quote!( items.push(quote!(
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -22,12 +21,6 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
static #exec_name: static #exec_name:
rtic::RacyCell<rtic::export::executor::AsyncTaskExecutor<#type_name>> = rtic::RacyCell<rtic::export::executor::AsyncTaskExecutor<#type_name>> =
rtic::RacyCell::new(rtic::export::executor::AsyncTaskExecutor::new()); rtic::RacyCell::new(rtic::export::executor::AsyncTaskExecutor::new());
// The executors priority, this can be any value - we will overwrite it when we
// start a task
#[allow(non_upper_case_globals)]
static #prio_name: rtic::RacyCell<rtic::export::Priority> =
unsafe { rtic::RacyCell::new(rtic::export::Priority::new(0)) };
)); ));
} }
@ -39,7 +32,6 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
for name in channel.tasks.iter() { for name in channel.tasks.iter() {
let exec_name = util::internal_task_ident(name, "EXEC"); let exec_name = util::internal_task_ident(name, "EXEC");
let prio_name = util::internal_task_ident(name, "PRIORITY");
// let task = &app.software_tasks[name]; // let task = &app.software_tasks[name];
// let cfgs = &task.cfgs; // let cfgs = &task.cfgs;
let executor_run_ident = util::executor_run_ident(name); let executor_run_ident = util::executor_run_ident(name);
@ -57,14 +49,9 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
if !(&*#exec_name.get()).is_running() { if !(&*#exec_name.get()).is_running() {
// TODO Fix this to be compare and swap // TODO Fix this to be compare and swap
if #rq.load(core::sync::atomic::Ordering::Relaxed) { if #rq.load(core::sync::atomic::Ordering::Relaxed) {
#rq.store(false, core::sync::atomic::Ordering::Relaxed); #rq.store(false, core::sync::atomic::Ordering::Relaxed);
(&mut *#exec_name.get_mut()).spawn(#name(#name::Context::new()));
// The async executor needs a static priority
#prio_name.get_mut().write(rtic::export::Priority::new(PRIORITY));
let priority: &'static _ = &*#prio_name.get();
(&mut *#exec_name.get_mut()).spawn(#name(#name::Context::new(priority)));
#executor_run_ident.store(true, core::sync::atomic::Ordering::Relaxed); #executor_run_ident.store(true, core::sync::atomic::Ordering::Relaxed);
} }
} }

View file

@ -41,22 +41,16 @@ pub fn codegen(
rtic::export::run(PRIORITY, || { rtic::export::run(PRIORITY, || {
#name( #name(
#name::Context::new(&rtic::export::Priority::new(PRIORITY)) #name::Context::new()
) )
}); });
} }
)); ));
let mut shared_needs_lt = false;
let mut local_needs_lt = false;
// `${task}Locals` // `${task}Locals`
if !task.args.local_resources.is_empty() { if !task.args.local_resources.is_empty() {
let (item, constructor) = local_resources_struct::codegen( let (item, constructor) =
Context::HardwareTask(name), local_resources_struct::codegen(Context::HardwareTask(name), app);
&mut local_needs_lt,
app,
);
root.push(item); root.push(item);
@ -65,24 +59,19 @@ pub fn codegen(
// `${task}Resources` // `${task}Resources`
if !task.args.shared_resources.is_empty() { if !task.args.shared_resources.is_empty() {
let (item, constructor) = shared_resources_struct::codegen( let (item, constructor) =
Context::HardwareTask(name), shared_resources_struct::codegen(Context::HardwareTask(name), app);
&mut shared_needs_lt,
app,
);
root.push(item); root.push(item);
mod_app.push(constructor); mod_app.push(constructor);
} }
root.push(module::codegen( // Module generation...
Context::HardwareTask(name),
shared_needs_lt, root.push(module::codegen(Context::HardwareTask(name), app, analysis));
local_needs_lt,
app, // End module generation
analysis,
));
if !task.is_extern { if !task.is_extern {
let attrs = &task.attrs; let attrs = &task.attrs;

View file

@ -24,37 +24,27 @@ pub fn codegen(
TokenStream2, TokenStream2,
) { ) {
if let Some(idle) = &app.idle { if let Some(idle) = &app.idle {
let mut shared_needs_lt = false;
let mut local_needs_lt = false;
let mut mod_app = vec![]; let mut mod_app = vec![];
let mut root_idle = vec![]; let mut root_idle = vec![];
let name = &idle.name; let name = &idle.name;
if !idle.args.shared_resources.is_empty() { if !idle.args.shared_resources.is_empty() {
let (item, constructor) = let (item, constructor) = shared_resources_struct::codegen(Context::Idle, app);
shared_resources_struct::codegen(Context::Idle, &mut shared_needs_lt, app);
root_idle.push(item); root_idle.push(item);
mod_app.push(constructor); mod_app.push(constructor);
} }
if !idle.args.local_resources.is_empty() { if !idle.args.local_resources.is_empty() {
let (item, constructor) = let (item, constructor) = local_resources_struct::codegen(Context::Idle, app);
local_resources_struct::codegen(Context::Idle, &mut local_needs_lt, app);
root_idle.push(item); root_idle.push(item);
mod_app.push(constructor); mod_app.push(constructor);
} }
root_idle.push(module::codegen( root_idle.push(module::codegen(Context::Idle, app, analysis));
Context::Idle,
shared_needs_lt,
local_needs_lt,
app,
analysis,
));
let attrs = &idle.attrs; let attrs = &idle.attrs;
let context = &idle.context; let context = &idle.context;
@ -71,7 +61,7 @@ pub fn codegen(
)); ));
let call_idle = quote!(#name( let call_idle = quote!(#name(
#name::Context::new(&rtic::export::Priority::new(0)) #name::Context::new()
)); ));
(mod_app, root_idle, user_idle, call_idle) (mod_app, root_idle, user_idle, call_idle)

View file

@ -91,8 +91,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> CodegenResult {
// `${task}Locals` // `${task}Locals`
if !init.args.local_resources.is_empty() { if !init.args.local_resources.is_empty() {
let (item, constructor) = let (item, constructor) = local_resources_struct::codegen(Context::Init, app);
local_resources_struct::codegen(Context::Init, &mut local_needs_lt, app);
root_init.push(item); root_init.push(item);
@ -103,13 +102,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> CodegenResult {
let (shared_resources, local_resources) = #name(#name::Context::new(core.into())); let (shared_resources, local_resources) = #name(#name::Context::new(core.into()));
}; };
root_init.push(module::codegen( root_init.push(module::codegen(Context::Init, app, analysis));
Context::Init,
false,
local_needs_lt,
app,
analysis,
));
(mod_app, root_init, user_init, call_init) (mod_app, root_init, user_init, call_init)
} }

View file

@ -8,7 +8,7 @@ use quote::quote;
use crate::codegen::util; use crate::codegen::util;
/// Generates local resources structs /// Generates local resources structs
pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2, TokenStream2) { pub fn codegen(ctxt: Context, app: &App) -> (TokenStream2, TokenStream2) {
let mut lt = None; let mut lt = None;
let resources = match ctxt { let resources = match ctxt {
@ -74,16 +74,14 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
} }
if lt.is_some() { if lt.is_some() {
*needs_lt = true;
// The struct could end up empty due to `cfg`s leading to an error due to `'a` being unused // The struct could end up empty due to `cfg`s leading to an error due to `'a` being unused
if has_cfgs { if has_cfgs {
fields.push(quote!( fields.push(quote!(
#[doc(hidden)] #[doc(hidden)]
pub __marker__: core::marker::PhantomData<&'a ()> pub __rtic_internal_marker: ::core::marker::PhantomData<&'a ()>
)); ));
values.push(quote!(__marker__: core::marker::PhantomData)); values.push(quote!(__rtic_internal_marker: ::core::marker::PhantomData));
} }
} }

View file

@ -4,13 +4,7 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::quote; use quote::quote;
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub fn codegen( pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
ctxt: Context,
shared_resources_tick: bool,
local_resources_tick: bool,
app: &App,
analysis: &Analysis,
) -> TokenStream2 {
let mut items = vec![]; let mut items = vec![];
let mut module_items = vec![]; let mut module_items = vec![];
let mut fields = vec![]; let mut fields = vec![];
@ -20,7 +14,6 @@ pub fn codegen(
let name = ctxt.ident(app); let name = ctxt.ident(app);
let mut lt = None;
match ctxt { match ctxt {
Context::Init => { Context::Init => {
fields.push(quote!( fields.push(quote!(
@ -39,10 +32,9 @@ pub fn codegen(
values.push(quote!(device: #device::Peripherals::steal())); values.push(quote!(device: #device::Peripherals::steal()));
} }
lt = Some(quote!('a));
fields.push(quote!( fields.push(quote!(
/// Critical section token for init /// Critical section token for init
pub cs: rtic::export::CriticalSection<#lt> pub cs: rtic::export::CriticalSection<'a>
)); ));
values.push(quote!(cs: rtic::export::CriticalSection::new())); values.push(quote!(cs: rtic::export::CriticalSection::new()));
@ -55,12 +47,6 @@ pub fn codegen(
if ctxt.has_local_resources(app) { if ctxt.has_local_resources(app) {
let ident = util::local_resources_ident(ctxt, app); let ident = util::local_resources_ident(ctxt, app);
let lt = if local_resources_tick {
lt = Some(quote!('a));
Some(quote!('a))
} else {
None
};
module_items.push(quote!( module_items.push(quote!(
#[doc(inline)] #[doc(inline)]
@ -69,7 +55,7 @@ pub fn codegen(
fields.push(quote!( fields.push(quote!(
/// Local Resources this task has access to /// Local Resources this task has access to
pub local: #name::LocalResources<#lt> pub local: #name::LocalResources<'a>
)); ));
values.push(quote!(local: #name::LocalResources::new())); values.push(quote!(local: #name::LocalResources::new()));
@ -77,12 +63,6 @@ pub fn codegen(
if ctxt.has_shared_resources(app) { if ctxt.has_shared_resources(app) {
let ident = util::shared_resources_ident(ctxt, app); let ident = util::shared_resources_ident(ctxt, app);
let lt = if shared_resources_tick {
lt = Some(quote!('a));
Some(quote!('a))
} else {
None
};
module_items.push(quote!( module_items.push(quote!(
#[doc(inline)] #[doc(inline)]
@ -91,15 +71,10 @@ pub fn codegen(
fields.push(quote!( fields.push(quote!(
/// Shared Resources this task has access to /// Shared Resources this task has access to
pub shared: #name::SharedResources<#lt> pub shared: #name::SharedResources<'a>
)); ));
let priority = if ctxt.is_init() { values.push(quote!(shared: #name::SharedResources::new()));
None
} else {
Some(quote!(priority))
};
values.push(quote!(shared: #name::SharedResources::new(#priority)));
} }
let doc = match ctxt { let doc = match ctxt {
@ -122,12 +97,6 @@ pub fn codegen(
None None
}; };
let priority = if ctxt.is_init() {
None
} else {
Some(quote!(priority: &#lt rtic::export::Priority))
};
let internal_context_name = util::internal_task_ident(name, "Context"); let internal_context_name = util::internal_task_ident(name, "Context");
items.push(quote!( items.push(quote!(
@ -135,15 +104,18 @@ pub fn codegen(
/// Execution context /// Execution context
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub struct #internal_context_name<#lt> { pub struct #internal_context_name<'a> {
#[doc(hidden)]
__rtic_internal_p: ::core::marker::PhantomData<&'a ()>,
#(#fields,)* #(#fields,)*
} }
#(#cfgs)* #(#cfgs)*
impl<#lt> #internal_context_name<#lt> { impl<'a> #internal_context_name<'a> {
#[inline(always)] #[inline(always)]
pub unsafe fn new(#core #priority) -> Self { pub unsafe fn new(#core) -> Self {
#internal_context_name { #internal_context_name {
__rtic_internal_p: ::core::marker::PhantomData,
#(#values,)* #(#values,)*
} }
} }

View file

@ -57,19 +57,14 @@ pub fn codegen(
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#(#cfgs)* #(#cfgs)*
pub struct #shared_name<'a> { pub struct #shared_name<'a> {
priority: &'a Priority, __rtic_internal_p: ::core::marker::PhantomData<&'a ()>,
} }
#(#cfgs)* #(#cfgs)*
impl<'a> #shared_name<'a> { impl<'a> #shared_name<'a> {
#[inline(always)] #[inline(always)]
pub unsafe fn new(priority: &'a Priority) -> Self { pub unsafe fn new() -> Self {
#shared_name { priority } #shared_name { __rtic_internal_p: ::core::marker::PhantomData }
}
#[inline(always)]
pub unsafe fn priority(&self) -> &Priority {
self.priority
} }
} }
)); ));
@ -104,8 +99,6 @@ pub fn codegen(
quote!() quote!()
} else { } else {
quote!(mod shared_resources { quote!(mod shared_resources {
use rtic::export::Priority;
#(#mod_resources)* #(#mod_resources)*
}) })
}; };

View file

@ -5,7 +5,7 @@ use quote::quote;
use crate::codegen::util; use crate::codegen::util;
/// Generate shared resources structs /// Generate shared resources structs
pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2, TokenStream2) { pub fn codegen(ctxt: Context, app: &App) -> (TokenStream2, TokenStream2) {
let mut lt = None; let mut lt = None;
let resources = match ctxt { let resources = match ctxt {
@ -72,7 +72,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
values.push(quote!( values.push(quote!(
#(#cfgs)* #(#cfgs)*
#name: shared_resources::#shared_name::new(priority) #name: shared_resources::#shared_name::new()
)); ));
@ -93,8 +93,6 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
} }
if lt.is_some() { if lt.is_some() {
*needs_lt = true;
// The struct could end up empty due to `cfg`s leading to an error due to `'a` being unused // The struct could end up empty due to `cfg`s leading to an error due to `'a` being unused
if has_cfgs { if has_cfgs {
fields.push(quote!( fields.push(quote!(
@ -117,15 +115,10 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
} }
); );
let arg = if ctxt.is_init() {
None
} else {
Some(quote!(priority: &#lt rtic::export::Priority))
};
let constructor = quote!( let constructor = quote!(
impl<#lt> #ident<#lt> { impl<#lt> #ident<#lt> {
#[inline(always)] #[inline(always)]
pub unsafe fn new(#arg) -> Self { pub unsafe fn new() -> Self {
#ident { #ident {
#(#values,)* #(#values,)*
} }

View file

@ -36,16 +36,11 @@ pub fn codegen(
)); ));
// `${task}Resources` // `${task}Resources`
let mut shared_needs_lt = false;
let mut local_needs_lt = false;
// `${task}Locals` // `${task}Locals`
if !task.args.local_resources.is_empty() { if !task.args.local_resources.is_empty() {
let (item, constructor) = local_resources_struct::codegen( let (item, constructor) =
Context::SoftwareTask(name), local_resources_struct::codegen(Context::SoftwareTask(name), app);
&mut local_needs_lt,
app,
);
root.push(item); root.push(item);
@ -53,11 +48,8 @@ pub fn codegen(
} }
if !task.args.shared_resources.is_empty() { if !task.args.shared_resources.is_empty() {
let (item, constructor) = shared_resources_struct::codegen( let (item, constructor) =
Context::SoftwareTask(name), shared_resources_struct::codegen(Context::SoftwareTask(name), app);
&mut shared_needs_lt,
app,
);
root.push(item); root.push(item);
@ -69,17 +61,12 @@ pub fn codegen(
let attrs = &task.attrs; let attrs = &task.attrs;
let cfgs = &task.cfgs; let cfgs = &task.cfgs;
let stmts = &task.stmts; let stmts = &task.stmts;
let context_lifetime = if shared_needs_lt || local_needs_lt {
quote!(<'static>)
} else {
quote!()
};
user_tasks.push(quote!( user_tasks.push(quote!(
#(#attrs)* #(#attrs)*
#(#cfgs)* #(#cfgs)*
#[allow(non_snake_case)] #[allow(non_snake_case)]
async fn #name(#context: #name::Context #context_lifetime) { async fn #name(#context: #name::Context<'static>) {
use rtic::Mutex as _; use rtic::Mutex as _;
use rtic::mutex::prelude::*; use rtic::mutex::prelude::*;
@ -88,13 +75,7 @@ pub fn codegen(
)); ));
} }
root.push(module::codegen( root.push(module::codegen(Context::SoftwareTask(name), app, analysis));
Context::SoftwareTask(name),
shared_needs_lt,
local_needs_lt,
app,
analysis,
));
} }
(mod_app, root, user_tasks) (mod_app, root, user_tasks)

View file

@ -17,10 +17,10 @@ pub fn impl_mutex(
ceiling: u8, ceiling: u8,
ptr: &TokenStream2, ptr: &TokenStream2,
) -> TokenStream2 { ) -> TokenStream2 {
let (path, priority) = if resources_prefix { let path = if resources_prefix {
(quote!(shared_resources::#name), quote!(self.priority())) quote!(shared_resources::#name)
} else { } else {
(quote!(#name), quote!(self.priority)) quote!(#name)
}; };
let device = &app.args.device; let device = &app.args.device;
@ -38,7 +38,6 @@ pub fn impl_mutex(
unsafe { unsafe {
rtic::export::lock( rtic::export::lock(
#ptr, #ptr,
#priority,
CEILING, CEILING,
#device::NVIC_PRIO_BITS, #device::NVIC_PRIO_BITS,
&#masks_name, &#masks_name,

View file

@ -1,4 +1,4 @@
[toolchain] [toolchain]
channel = "nightly" channel = "nightly"
components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] components = [ "rust-src", "rustfmt", "llvm-tools-preview" ]
targets = [ "thumbv7em-none-eabihf" ] targets = [ "thumbv6m-none-eabi", "thumbv7m-none-eabi" ]

View file

@ -163,38 +163,6 @@ impl Barrier {
} }
} }
// Newtype over `Cell` that forbids mutation through a shared reference
pub struct Priority {
inner: Cell<u8>,
}
impl Priority {
/// Create a new Priority
///
/// # Safety
///
/// Will overwrite the current Priority
#[inline(always)]
pub const unsafe fn new(value: u8) -> Self {
Priority {
inner: Cell::new(value),
}
}
/// Change the current priority to `value`
// These two methods are used by `lock` (see below) but can't be used from the RTIC application
#[inline(always)]
fn set(&self, value: u8) {
self.inner.set(value);
}
/// Get the current priority
#[inline(always)]
fn get(&self) -> u8 {
self.inner.get()
}
}
/// Const helper to check architecture /// Const helper to check architecture
pub const fn have_basepri() -> bool { pub const fn have_basepri() -> bool {
#[cfg(have_basepri)] #[cfg(have_basepri)]
@ -260,30 +228,20 @@ where
#[inline(always)] #[inline(always)]
pub unsafe fn lock<T, R, const M: usize>( pub unsafe fn lock<T, R, const M: usize>(
ptr: *mut T, ptr: *mut T,
priority: &Priority,
ceiling: u8, ceiling: u8,
nvic_prio_bits: u8, nvic_prio_bits: u8,
_mask: &[Mask<M>; 3], _mask: &[Mask<M>; 3],
f: impl FnOnce(&mut T) -> R, f: impl FnOnce(&mut T) -> R,
) -> R { ) -> R {
let current = priority.get(); if ceiling == (1 << nvic_prio_bits) {
let r = interrupt::free(|_| f(&mut *ptr));
if current < ceiling { r
if ceiling == (1 << nvic_prio_bits) {
priority.set(u8::max_value());
let r = interrupt::free(|_| f(&mut *ptr));
priority.set(current);
r
} else {
priority.set(ceiling);
basepri::write(logical2hw(ceiling, nvic_prio_bits));
let r = f(&mut *ptr);
basepri::write(logical2hw(current, nvic_prio_bits));
priority.set(current);
r
}
} else { } else {
f(&mut *ptr) let current = basepri::read();
basepri::write(logical2hw(ceiling, nvic_prio_bits));
let r = f(&mut *ptr);
basepri::write(logical2hw(current, nvic_prio_bits));
r
} }
} }
@ -335,40 +293,29 @@ pub unsafe fn lock<T, R, const M: usize>(
#[inline(always)] #[inline(always)]
pub unsafe fn lock<T, R, const M: usize>( pub unsafe fn lock<T, R, const M: usize>(
ptr: *mut T, ptr: *mut T,
priority: &Priority,
ceiling: u8, ceiling: u8,
_nvic_prio_bits: u8, _nvic_prio_bits: u8,
masks: &[Mask<M>; 3], masks: &[Mask<M>; 3],
f: impl FnOnce(&mut T) -> R, f: impl FnOnce(&mut T) -> R,
) -> R { ) -> R {
let current = priority.get(); if ceiling >= 4 {
if current < ceiling { // safe to manipulate outside critical section
if ceiling >= 4 { // execute closure under protection of raised system ceiling
// safe to manipulate outside critical section let r = interrupt::free(|_| f(&mut *ptr));
priority.set(ceiling); // safe to manipulate outside critical section
// execute closure under protection of raised system ceiling r
let r = interrupt::free(|_| f(&mut *ptr));
// safe to manipulate outside critical section
priority.set(current);
r
} else {
// safe to manipulate outside critical section
priority.set(ceiling);
let mask = compute_mask(current, ceiling, masks);
clear_enable_mask(mask);
// execute closure under protection of raised system ceiling
let r = f(&mut *ptr);
set_enable_mask(mask);
// safe to manipulate outside critical section
priority.set(current);
r
}
} else { } else {
// execute closure without raising system ceiling // safe to manipulate outside critical section
f(&mut *ptr) let mask = compute_mask(0, ceiling, masks);
clear_enable_mask(mask);
// execute closure under protection of raised system ceiling
let r = f(&mut *ptr);
set_enable_mask(mask);
// safe to manipulate outside critical section
r
} }
} }