mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-25 21:19:35 +01:00
add debug assertions to lock
and get
This commit is contained in:
parent
f3b73bcc12
commit
4c1b6c8293
1 changed files with 120 additions and 204 deletions
324
src/lib.rs
324
src/lib.rs
|
@ -12,7 +12,7 @@ extern crate cortex_m;
|
|||
|
||||
use cortex_m::ctxt::Context;
|
||||
use cortex_m::interrupt::CriticalSection;
|
||||
use cortex_m::peripheral::Peripheral;
|
||||
use cortex_m::peripheral::{Peripheral, NVIC, SCB};
|
||||
use cortex_m::register::{basepri, basepri_max};
|
||||
|
||||
use core::cell::UnsafeCell;
|
||||
|
@ -23,6 +23,34 @@ use core::ptr;
|
|||
// considered when determining priorities.
|
||||
const PRIORITY_BITS: u8 = 4;
|
||||
|
||||
/// Logical task priority
|
||||
unsafe fn task_priority() -> u8 {
|
||||
// NOTE(safe) atomic read
|
||||
let nr = match (*SCB.get()).icsr.read() as u8 {
|
||||
n if n >= 16 => n - 16,
|
||||
_ => panic!("not in a task"),
|
||||
};
|
||||
// NOTE(safe) atomic read
|
||||
hardware((*NVIC.get()).ipr[nr as usize].read())
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
unsafe fn lock_check(ceiling: u8) {
|
||||
let ceiling = hardware(ceiling);
|
||||
let task_priority = task_priority();
|
||||
|
||||
if task_priority > ceiling {
|
||||
panic!(
|
||||
"bad ceiling value. task_priority = {}, resource_ceiling = {}",
|
||||
task_priority,
|
||||
ceiling,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
unsafe fn lock_check(_ceiling: u8) {}
|
||||
|
||||
// XXX Do we need memory / instruction / compiler barriers here?
|
||||
#[inline(always)]
|
||||
unsafe fn lock<T, R, C, F>(f: F, res: *const T, ceiling: u8) -> R
|
||||
|
@ -30,6 +58,7 @@ where
|
|||
C: Ceiling,
|
||||
F: FnOnce(&T, C) -> R,
|
||||
{
|
||||
lock_check(ceiling);
|
||||
let old_basepri = basepri::read();
|
||||
basepri_max::write(ceiling);
|
||||
let ret = f(&*res, ptr::read(0 as *const _));
|
||||
|
@ -44,6 +73,7 @@ where
|
|||
C: Ceiling,
|
||||
F: FnOnce(&mut T, C) -> R,
|
||||
{
|
||||
lock_check(ceiling);
|
||||
let old_basepri = basepri::read();
|
||||
basepri_max::write(ceiling);
|
||||
let ret = f(&mut *res, ptr::read(0 as *const _));
|
||||
|
@ -131,7 +161,7 @@ where
|
|||
F: FnOnce(&P, C) -> R,
|
||||
Ctxt: Context,
|
||||
{
|
||||
unsafe { lock(f, self.peripheral.get(), C::ceiling()) }
|
||||
unsafe { lock(f, self.peripheral.get(), C::hw_ceiling()) }
|
||||
}
|
||||
|
||||
/// Mutably locks the resource, preventing tasks with priority lower than
|
||||
|
@ -141,7 +171,7 @@ where
|
|||
F: FnOnce(&mut P, C) -> R,
|
||||
Ctxt: Context,
|
||||
{
|
||||
unsafe { lock_mut(f, self.peripheral.get(), C::ceiling()) }
|
||||
unsafe { lock_mut(f, self.peripheral.get(), C::hw_ceiling()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,9 +259,43 @@ where
|
|||
unsafe { &mut *self.data.get() }
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer to the wrapped value
|
||||
pub fn get(&self) -> *mut T {
|
||||
self.data.get()
|
||||
/// Returns a mutable reference to the wrapped value
|
||||
pub unsafe fn get(&self) -> &'static mut T {
|
||||
match () {
|
||||
#[cfg(debug_assertions)]
|
||||
() => {
|
||||
let task_priority = task_priority();
|
||||
let system_ceiling =
|
||||
hardware(cortex_m::register::basepri::read());
|
||||
let resource_ceiling = C::ceiling();
|
||||
|
||||
if resource_ceiling < task_priority {
|
||||
panic!("bad ceiling value. task priority = {}, \
|
||||
resource ceiling = {}",
|
||||
task_priority,
|
||||
resource_ceiling);
|
||||
} else if resource_ceiling == task_priority {
|
||||
// OK: safe to access the resource without locking in the
|
||||
// task with highest priority
|
||||
} else if resource_ceiling <= system_ceiling {
|
||||
// OK: use within another resource critical section, where
|
||||
// the locked resource has higher or equal ceiling
|
||||
} else {
|
||||
panic!("racy access to resource. \
|
||||
task priority = {}, \
|
||||
resource ceiling = {}, \
|
||||
system ceiling = {}",
|
||||
task_priority,
|
||||
resource_ceiling,
|
||||
system_ceiling);
|
||||
}
|
||||
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
() => {}
|
||||
}
|
||||
|
||||
&mut *self.data.get()
|
||||
}
|
||||
|
||||
/// Locks the resource, preventing tasks with priority lower than `Ceiling`
|
||||
|
@ -241,7 +305,7 @@ where
|
|||
F: FnOnce(&T, C) -> R,
|
||||
Ctxt: Context,
|
||||
{
|
||||
unsafe { lock(f, self.data.get(), C::ceiling()) }
|
||||
unsafe { lock(f, self.data.get(), C::hw_ceiling()) }
|
||||
}
|
||||
|
||||
/// Mutably locks the resource, preventing tasks with priority lower than
|
||||
|
@ -251,7 +315,7 @@ where
|
|||
F: FnOnce(&mut T, C) -> R,
|
||||
Ctxt: Context,
|
||||
{
|
||||
unsafe { lock_mut(f, self.data.get(), C::ceiling()) }
|
||||
unsafe { lock_mut(f, self.data.get(), C::hw_ceiling()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,6 +342,11 @@ impl<T> Resource<T, C0> {
|
|||
|
||||
unsafe impl<T, Ceiling> Sync for Resource<T, Ceiling> {}
|
||||
|
||||
/// Maps a hardware priority to a logical priority
|
||||
fn hardware(priority: u8) -> u8 {
|
||||
16 - (priority >> (8 - PRIORITY_BITS))
|
||||
}
|
||||
|
||||
/// Turns a `logical` priority into a NVIC-style priority
|
||||
///
|
||||
/// With `logical` priorities, `2` has HIGHER priority than `1`.
|
||||
|
@ -298,86 +367,14 @@ pub struct C0 {
|
|||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C1 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C2 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C3 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C4 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C5 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C6 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C7 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C8 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C9 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C10 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C11 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C12 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C13 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C14 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// Ceiling
|
||||
pub struct C15 {
|
||||
_0: (),
|
||||
}
|
||||
|
||||
/// A real ceiling
|
||||
// XXX this should be a "closed" trait
|
||||
pub unsafe trait Ceiling {
|
||||
/// Returns the ceiling as a number
|
||||
/// Returns the logical ceiling as a number
|
||||
fn ceiling() -> u8;
|
||||
|
||||
/// Returns the HW ceiling as a number
|
||||
fn hw_ceiling() -> u8;
|
||||
}
|
||||
|
||||
/// Usable as a ceiling
|
||||
|
@ -388,6 +385,45 @@ pub unsafe trait CeilingLike {}
|
|||
// XXX this should be a "closed" trait
|
||||
pub unsafe trait HigherThan<C> {}
|
||||
|
||||
macro_rules! ceiling {
|
||||
($ceiling:ident, $logical:expr) => {
|
||||
/// Ceiling
|
||||
pub struct $ceiling {
|
||||
_0: ()
|
||||
}
|
||||
|
||||
unsafe impl CeilingLike for $ceiling {}
|
||||
|
||||
unsafe impl Ceiling for $ceiling {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
$logical
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn hw_ceiling() -> u8 {
|
||||
((1 << PRIORITY_BITS) - $logical) << (8 - PRIORITY_BITS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ceiling!(C1, 1);
|
||||
ceiling!(C2, 2);
|
||||
ceiling!(C3, 3);
|
||||
ceiling!(C4, 4);
|
||||
ceiling!(C5, 5);
|
||||
ceiling!(C6, 6);
|
||||
ceiling!(C7, 7);
|
||||
ceiling!(C8, 8);
|
||||
ceiling!(C9, 9);
|
||||
ceiling!(C10, 10);
|
||||
ceiling!(C11, 11);
|
||||
ceiling!(C12, 12);
|
||||
ceiling!(C13, 13);
|
||||
ceiling!(C14, 14);
|
||||
ceiling!(C15, 15);
|
||||
|
||||
unsafe impl HigherThan<C1> for C2 {}
|
||||
unsafe impl HigherThan<C1> for C3 {}
|
||||
unsafe impl HigherThan<C1> for C4 {}
|
||||
|
@ -507,124 +543,4 @@ unsafe impl HigherThan<C13> for C15 {}
|
|||
|
||||
unsafe impl HigherThan<C14> for C15 {}
|
||||
|
||||
unsafe impl Ceiling for C1 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 1) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C2 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 2) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C3 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 3) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C4 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 4) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C5 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 5) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C6 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 6) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C7 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 7) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C8 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 8) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C9 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 9) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C10 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 10) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C11 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 11) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C12 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 12) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C13 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 13) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C14 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 14) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Ceiling for C15 {
|
||||
#[inline(always)]
|
||||
fn ceiling() -> u8 {
|
||||
((1 << 4) - 15) << 4
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl CeilingLike for C0 {}
|
||||
unsafe impl CeilingLike for C1 {}
|
||||
unsafe impl CeilingLike for C2 {}
|
||||
unsafe impl CeilingLike for C3 {}
|
||||
unsafe impl CeilingLike for C4 {}
|
||||
unsafe impl CeilingLike for C5 {}
|
||||
unsafe impl CeilingLike for C6 {}
|
||||
unsafe impl CeilingLike for C7 {}
|
||||
unsafe impl CeilingLike for C8 {}
|
||||
unsafe impl CeilingLike for C9 {}
|
||||
unsafe impl CeilingLike for C10 {}
|
||||
unsafe impl CeilingLike for C11 {}
|
||||
unsafe impl CeilingLike for C12 {}
|
||||
unsafe impl CeilingLike for C13 {}
|
||||
unsafe impl CeilingLike for C14 {}
|
||||
unsafe impl CeilingLike for C15 {}
|
||||
|
|
Loading…
Reference in a new issue