diff --git a/rtic/CHANGELOG.md b/rtic/CHANGELOG.md index 815b1bb0df..83c2b196ca 100644 --- a/rtic/CHANGELOG.md +++ b/rtic/CHANGELOG.md @@ -13,6 +13,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top! ### Fixed +- **Soundness fix:** `thumbv7` was subject to priority inversion. - **Soundness fix:** Monotonics did not wait long enough in `Duration` based delays. This is not directly a change for `rtic`, but required bumping the minimal version of `rtic-monotonics`. diff --git a/rtic/ci/expected/prio-inversion.run b/rtic/ci/expected/prio-inversion.run new file mode 100644 index 0000000000..91914362f1 --- /dev/null +++ b/rtic/ci/expected/prio-inversion.run @@ -0,0 +1,6 @@ +foo - start +pre baz spawn 0 0 +post baz spawn 0 0 + baz - start + baz - end +foo - end diff --git a/rtic/examples/prio-inversion.rs b/rtic/examples/prio-inversion.rs new file mode 100644 index 0000000000..1c2f7fd851 --- /dev/null +++ b/rtic/examples/prio-inversion.rs @@ -0,0 +1,87 @@ +//! examples/prio-inversion.rs +//! +//! Here we test to make sure we don't have priority inversion. + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] +#![feature(type_alias_impl_trait)] + +use panic_semihosting as _; +use rtic::app; + +// t1 p1 use b, a +// t2 p2 use a +// t3 p3 +// t4 p4 use b +// +// so t1 start , take b take a, pend t3 +// t3 should not start +// try to see if it starts, IT SHOULD NOT + +#[app(device = lm3s6965, dispatchers = [SSI0, QEI0, GPIOA, GPIOB])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + a: u32, + b: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + + (Shared { a: 0, b: 0 }, Local {}) + } + + #[task(priority = 1, shared = [a, b])] + async fn foo(cx: foo::Context) { + let foo::SharedResources { mut a, mut b, .. } = cx.shared; + + hprintln!("foo - start"); + + // basepri = 0 + b.lock(|b| { + // basepri = max(basepri = 0, ceil(b) = 4) = 4 + a.lock(|a| { + // basepri = max(basepri = 4, ceil(a) = 2) = 4 + + hprintln!("pre baz spawn {} {}", a, b); + + // This spawn should be blocked as prio(baz) = 3 + baz::spawn().unwrap(); + + hprintln!("post baz spawn {} {}", a, b); + }); + // basepri = 4 + }); + // basepri = 0 + + hprintln!("foo - end"); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + #[task(priority = 2, shared = [a])] + async fn bar(_: bar::Context) { + hprintln!(" bar"); + } + + #[task(priority = 3)] + async fn baz(_: baz::Context) { + hprintln!(" baz - start"); + hprintln!(" baz - end"); + } + + #[task(priority = 4, shared = [b])] + async fn pow(_: pow::Context) { + hprintln!(" pow - start"); + hprintln!(" pow - end"); + } +} diff --git a/rtic/src/export/cortex_basepri.rs b/rtic/src/export/cortex_basepri.rs index 14017543d1..8aaa2d411e 100644 --- a/rtic/src/export/cortex_basepri.rs +++ b/rtic/src/export/cortex_basepri.rs @@ -1,5 +1,5 @@ use super::cortex_logical2hw; -use cortex_m::register::basepri; +use cortex_m::register::{basepri, basepri_max}; pub use cortex_m::{ asm::wfi, interrupt, @@ -73,7 +73,7 @@ pub unsafe fn lock( critical_section::with(|_| f(&mut *ptr)) } else { let current = basepri::read(); - basepri::write(cortex_logical2hw(ceiling, nvic_prio_bits)); + basepri_max::write(cortex_logical2hw(ceiling, nvic_prio_bits)); let r = f(&mut *ptr); basepri::write(current); r