mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-23 20:22:51 +01:00
failed attempt at new claim
This commit is contained in:
parent
8e0569c396
commit
9ede9215c2
1 changed files with 265 additions and 171 deletions
436
src/lib.rs
436
src/lib.rs
|
@ -423,71 +423,6 @@ impl<T, CEILING> Res<T, C<CEILING>> {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// / Locks the resource for the duration of the critical section `f`
|
|
||||||
// /
|
|
||||||
// / For the duration of the critical section, tasks whose priority level is
|
|
||||||
// / smaller than or equal to the resource `CEILING` will be prevented from
|
|
||||||
// / preempting the current task.
|
|
||||||
// /
|
|
||||||
// / Within this critical section, resources with ceiling equal to or smaller
|
|
||||||
// / than `CEILING` can be borrowed at zero cost. See
|
|
||||||
// / [Resource.borrow](struct.Resource.html#method.borrow).
|
|
||||||
// #[cfg(not(thumbv6m))]
|
|
||||||
// pub fn claim_mut<R, PRIOTASK, CURRCEIL, F>(
|
|
||||||
// &'static self,
|
|
||||||
// _prio: &P<PRIOTASK>,
|
|
||||||
// _curr_ceil: &C<CURRCEIL>,
|
|
||||||
// f: F,
|
|
||||||
// ) -> R
|
|
||||||
// where
|
|
||||||
// F: FnOnce(&mut T, &C<<CEILING as Max<CURRCEIL>>::Output>) -> R,
|
|
||||||
// PRIOTASK: Unsigned,
|
|
||||||
// CURRCEIL: Unsigned,
|
|
||||||
// CEILING: GreaterThanOrEqual<PRIOTASK> + Max<CURRCEIL> + Level + Unsigned,
|
|
||||||
// {
|
|
||||||
// unsafe {
|
|
||||||
// match self._state.get() {
|
|
||||||
// State::Free => {
|
|
||||||
// let c1 = <CURRCEIL>::to_u8();
|
|
||||||
// let c2 = <CEILING>::to_u8();
|
|
||||||
// if c2 > c1 {
|
|
||||||
// let old_basepri = basepri::read();
|
|
||||||
// basepri_max::write(<CEILING>::hw());
|
|
||||||
// barrier!();
|
|
||||||
// self._state.set(State::LockedMut);
|
|
||||||
// barrier!();
|
|
||||||
//
|
|
||||||
// let ret = f(
|
|
||||||
// &mut *self.data.get(),
|
|
||||||
// &C { _marker: PhantomData },
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// barrier!();
|
|
||||||
// self._state.set(State::Free);
|
|
||||||
// barrier!();
|
|
||||||
// basepri::write(old_basepri);
|
|
||||||
// ret
|
|
||||||
// } else {
|
|
||||||
// self._state.set(State::LockedMut);
|
|
||||||
// barrier!();
|
|
||||||
//
|
|
||||||
// let ret = f(
|
|
||||||
// &mut *self.data.get(),
|
|
||||||
// &C { _marker: PhantomData },
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// barrier!();
|
|
||||||
// self._state.set(State::Free);
|
|
||||||
// ret
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// _ => panic!("Resource already locked)"),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, C> Sync for Res<T, C>
|
unsafe impl<T, C> Sync for Res<T, C>
|
||||||
|
@ -496,145 +431,304 @@ where
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
// re-implementation of the original claim API
|
/// Nem attempt
|
||||||
impl<T, CEILING> Res<T, C<CEILING>> {
|
use core::cell::RefCell;
|
||||||
/// Locks the resource for the duration of the critical section `f`
|
use core::cell::RefMut;
|
||||||
///
|
|
||||||
/// For the duration of the critical section, tasks whose priority level is
|
//use core::borrow::BorrowMut;
|
||||||
/// smaller than or equal to the resource `CEILING` will be prevented from
|
/// A resource
|
||||||
/// preempting the current task.
|
pub struct ResRef<T, CEILING> {
|
||||||
///
|
_ceiling: PhantomData<CEILING>,
|
||||||
/// Within this critical section, resources with ceiling equal to or smaller
|
data: UnsafeCell<RefCell<T>>,
|
||||||
/// than `CEILING` can be borrowed at zero cost. See
|
}
|
||||||
/// [Resource.borrow](struct.Resource.html#method.borrow).
|
|
||||||
#[cfg(not(thumbv6m))]
|
impl<T, C> ResRef<T, C> {
|
||||||
pub fn claim<R, PRIOTASK, CURRCEIL, F>(
|
/// Creates a new resource with ceiling `C`
|
||||||
&'static self,
|
pub const fn new(data: T) -> Self
|
||||||
_prio: &P<PRIOTASK>,
|
|
||||||
_curr_ceil: &C<CURRCEIL>,
|
|
||||||
f: F,
|
|
||||||
) -> R
|
|
||||||
where
|
where
|
||||||
F: FnOnce(Ref<T>, &C<<CEILING as Max<CURRCEIL>>::Output>) -> R,
|
C: Ceiling,
|
||||||
PRIOTASK: Unsigned,
|
|
||||||
CURRCEIL: Unsigned,
|
|
||||||
CEILING: GreaterThanOrEqual<PRIOTASK> + Max<CURRCEIL> + Level + Unsigned,
|
|
||||||
{
|
{
|
||||||
|
ResRef {
|
||||||
match self._state.get() {
|
_ceiling: PhantomData,
|
||||||
State::LockedMut => panic!("Resource already locked)"),
|
data: UnsafeCell::new(RefCell::new(data)),
|
||||||
_ => unsafe {
|
|
||||||
let c1 = <CURRCEIL>::to_u8();
|
|
||||||
let c2 = <CEILING>::to_u8();
|
|
||||||
if c2 > c1 {
|
|
||||||
let old_basepri = basepri::read();
|
|
||||||
basepri_max::write(<CEILING>::hw());
|
|
||||||
barrier!();
|
|
||||||
let s = self._state.get();
|
|
||||||
self._state.set(State::LockedMut);
|
|
||||||
barrier!();
|
|
||||||
|
|
||||||
let ret = f(
|
|
||||||
Ref::new(&*self.data.get()),
|
|
||||||
&C { _marker: PhantomData },
|
|
||||||
);
|
|
||||||
|
|
||||||
barrier!();
|
|
||||||
self._state.set(s);
|
|
||||||
barrier!();
|
|
||||||
basepri::write(old_basepri);
|
|
||||||
ret
|
|
||||||
} else {
|
|
||||||
let s = self._state.get();
|
|
||||||
self._state.set(State::LockedMut);
|
|
||||||
barrier!();
|
|
||||||
|
|
||||||
let ret = f(
|
|
||||||
Ref::new(&*self.data.get()),
|
|
||||||
&C { _marker: PhantomData },
|
|
||||||
);
|
|
||||||
|
|
||||||
barrier!();
|
|
||||||
self._state.set(s);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, CEILING> ResRef<T, C<CEILING>> {
|
||||||
/// Locks the resource for the duration of the critical section `f`
|
/// Locks the resource for the duration of the critical section `f`
|
||||||
///
|
///
|
||||||
/// For the duration of the critical section, tasks whose priority level is
|
/// For the duration of the critical section, tasks whose priority level is
|
||||||
/// smaller than or equal to the resource `CEILING` will be prevented from
|
/// smaller than or equal to the resource `CEILING` will be prevented from
|
||||||
/// preempting the current task.
|
/// preempting the current task.
|
||||||
///
|
///
|
||||||
/// Within this critical section, resources with ceiling equal to or smaller
|
/// claim takes three args of type R, PRIOTASK, CURRCEIL, F
|
||||||
/// than `CEILING` can be borrowed at zero cost. See
|
/// R is the Resource to lock (self)
|
||||||
/// [Resource.borrow](struct.Resource.html#method.borrow).
|
/// PRIOTASK is the priority of the task (context) calling claim
|
||||||
|
/// CURRCEIL is the current system ceiling
|
||||||
|
///
|
||||||
|
/// F is the type of the closure, hande &T and &C
|
||||||
|
/// &T is a read only reference to the data
|
||||||
|
/// &C is the new system ceiling
|
||||||
|
///
|
||||||
|
/// Usage example: a task at prio P1, claiming R1 and R2.
|
||||||
|
/// fn j(_task: Exti0, p: P1) {
|
||||||
|
/// R1.claim_mut(
|
||||||
|
/// &p, &p.as_ceiling(), |a, c| {
|
||||||
|
/// R2.claim_mut(
|
||||||
|
/// &p, &c, |b, _| {
|
||||||
|
/// b.y = a[0]; // b is mutable
|
||||||
|
/// a[1] = b.y; // a is mutable
|
||||||
|
/// }
|
||||||
|
/// );
|
||||||
|
/// a[2] = 0; // a is mutable
|
||||||
|
/// }
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// The implementation satisfies the following
|
||||||
|
/// 1. Race free access to the resources under the Stack Resource Policy (SRP)
|
||||||
|
/// System ceiling SC, is implemented by the NVIC as MAX(TASKPRI, BASEPRPI)
|
||||||
|
/// Hence in case TASKPRI = SC, the BASEPRI register does not need to be updated
|
||||||
|
/// as checked by c2 > c1 (this an optimization)
|
||||||
|
///
|
||||||
|
/// 2. Static (compile time verification) that SC >= TASKPRI
|
||||||
|
/// This is achieved by the type bound CEILING: GreaterThanOrEqual<TASKPRI>
|
||||||
|
/// This gives ensurence that no task access a resoure with lower ceiling value than the task
|
||||||
|
/// and hence satisfies the soundness rule of SRP
|
||||||
|
///
|
||||||
|
/// 3. The system ceileng for the closure CS = MAX(CURRCEIL, R)
|
||||||
|
/// This is achieved by &C<<CEILING as Max<CURRCEIL>>::Output>
|
||||||
|
/// where Max operates on R and CEILING
|
||||||
|
///
|
||||||
|
/// 4. Rust aliasing rules are ensured as run-time check raises a panic if resourse state is locked
|
||||||
|
/// This resembles the RefCell implementation, but the implementation is more strict as multiple
|
||||||
|
/// readers are disallowed. Essentially this forbids re-locking
|
||||||
|
///
|
||||||
|
/// Usage example failing: a task at prio P1, claiming R1 and R1.
|
||||||
|
/// fn j(_task: Exti0, p: P1) {
|
||||||
|
/// R1.claim_mut(
|
||||||
|
/// &p, &p.as_ceiling(), |a1, c| {
|
||||||
|
/// R1.claim_mut( <-- at this point a panic will occur
|
||||||
|
/// &p, &c, |a2, _| {
|
||||||
|
/// }
|
||||||
|
/// );
|
||||||
|
/// a1[2] = 0; // a is mutable
|
||||||
|
/// }
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// 5. The ceiling of the closure cannot be leaked
|
||||||
|
///
|
||||||
|
/// fn jres_opt_leak(_task: Exti0, p: P1) {
|
||||||
|
/// R1.claim_mut(
|
||||||
|
/// &p, &p.as_ceiling(), |a, c| {
|
||||||
|
/// let leak_c = R2.claim_mut(&p, &c, |b, c| c); <-- trying to leak c as a return value
|
||||||
|
///
|
||||||
|
/// R5.claim_mut(&p, leak_c, |b, c| {}); <-- trying to use a leaked system ceilng
|
||||||
|
///
|
||||||
|
/// a[2] = 0;
|
||||||
|
/// }
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// The compiler will reject leakage due to the lifetime, (c in a closure is a &C, so it cannot be returned)
|
||||||
|
/// A leakage would indeed be fatal as claim would hand out an unprotected R
|
||||||
#[cfg(not(thumbv6m))]
|
#[cfg(not(thumbv6m))]
|
||||||
pub fn claim_mut<R, PRIOTASK, CURRCEIL, F>(
|
pub fn claim_mut<R, TASKPRI, CURRCEIL, F>(
|
||||||
&'static self,
|
&'static self,
|
||||||
_prio: &P<PRIOTASK>,
|
_prio: &P<TASKPRI>,
|
||||||
_curr_ceil: &C<CURRCEIL>,
|
_curr_ceil: &C<CURRCEIL>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> R
|
) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut T, &C<<CEILING as Max<CURRCEIL>>::Output>) -> R,
|
F: FnOnce(&mut T, &C<<CEILING as Max<CURRCEIL>>::Output>) -> R,
|
||||||
PRIOTASK: Unsigned,
|
TASKPRI: Unsigned,
|
||||||
CURRCEIL: Unsigned,
|
CURRCEIL: Unsigned,
|
||||||
CEILING: GreaterThanOrEqual<PRIOTASK> + Max<CURRCEIL> + Level + Unsigned,
|
CEILING: GreaterThanOrEqual<TASKPRI> + Max<CURRCEIL> + Level + Unsigned,
|
||||||
{
|
{
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
match self._state.get() {
|
let curr_ceil = <CURRCEIL>::to_u8();
|
||||||
State::Free => {
|
let new_ceil = <CEILING>::to_u8();
|
||||||
let c1 = <CURRCEIL>::to_u8();
|
if new_ceil > curr_ceil {
|
||||||
let c2 = <CEILING>::to_u8();
|
let old_basepri = basepri::read();
|
||||||
if c2 > c1 {
|
basepri_max::write(<CEILING>::hw());
|
||||||
let old_basepri = basepri::read();
|
barrier!();
|
||||||
basepri_max::write(<CEILING>::hw());
|
|
||||||
barrier!();
|
|
||||||
self._state.set(State::LockedMut);
|
|
||||||
barrier!();
|
|
||||||
|
|
||||||
let ret = f(
|
let r: &RefCell<T> = &*self.data.get();
|
||||||
&mut *self.data.get(),
|
let rr: RefCell<T> = *r;
|
||||||
&C { _marker: PhantomData },
|
let mut rm: RefMut<T> = rr.borrow_mut();
|
||||||
);
|
let mut t: T = *rm;
|
||||||
|
let ret = f(&mut t, &C { _marker: PhantomData });
|
||||||
|
|
||||||
barrier!();
|
barrier!();
|
||||||
self._state.set(State::Free);
|
basepri::write(old_basepri);
|
||||||
barrier!();
|
ret
|
||||||
basepri::write(old_basepri);
|
} else {
|
||||||
ret
|
panic!("");
|
||||||
} else {
|
|
||||||
self._state.set(State::LockedMut);
|
|
||||||
barrier!();
|
|
||||||
|
|
||||||
let ret = f(
|
|
||||||
&mut *self.data.get(),
|
|
||||||
&C { _marker: PhantomData },
|
|
||||||
);
|
|
||||||
|
|
||||||
barrier!();
|
|
||||||
self._state.set(State::Free);
|
|
||||||
ret
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("Resource already locked)"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, C> Sync for Res<T, C>
|
//
|
||||||
|
// /// Read only claim, see claim_mut above
|
||||||
|
// #[cfg(not(thumbv6m))]
|
||||||
|
// pub fn claim<R, TASKPRI, CURRCEIL, F>(
|
||||||
|
// &'static self,
|
||||||
|
// _prio: &P<TASKPRI>,
|
||||||
|
// _curr_ceil: &C<CURRCEIL>,
|
||||||
|
// f: F,
|
||||||
|
// ) -> R
|
||||||
|
// where
|
||||||
|
// F: FnOnce(&T, &C<<CEILING as Max<CURRCEIL>>::Output>) -> R,
|
||||||
|
// TASKPRI: Unsigned,
|
||||||
|
// CURRCEIL: Unsigned,
|
||||||
|
// CEILING: GreaterThanOrEqual<TASKPRI> + Max<CURRCEIL> + Level + Unsigned,
|
||||||
|
// {
|
||||||
|
// if self._state.get() {
|
||||||
|
// unsafe {
|
||||||
|
// let curr_ceil = <CURRCEIL>::to_u8();
|
||||||
|
// let new_ceil = <CEILING>::to_u8();
|
||||||
|
// if new_ceil > curr_ceil {
|
||||||
|
// let old_basepri = basepri::read();
|
||||||
|
// basepri_max::write(<CEILING>::hw());
|
||||||
|
// barrier!();
|
||||||
|
// self._state.set(false);
|
||||||
|
// barrier!();
|
||||||
|
//
|
||||||
|
// let ret = f(&*self.data.get(), &C { _marker: PhantomData });
|
||||||
|
//
|
||||||
|
// barrier!();
|
||||||
|
// self._state.set(true);
|
||||||
|
// barrier!();
|
||||||
|
// basepri::write(old_basepri);
|
||||||
|
// ret
|
||||||
|
// } else {
|
||||||
|
// self._state.set(false);
|
||||||
|
// barrier!();
|
||||||
|
//
|
||||||
|
// let ret = f(&*self.data.get(), &C { _marker: PhantomData });
|
||||||
|
//
|
||||||
|
// barrier!();
|
||||||
|
// self._state.set(true);
|
||||||
|
// ret
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// panic!("Resource already locked)")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /// Unsafe version of claim_mut
|
||||||
|
// #[cfg(not(thumbv6m))]
|
||||||
|
// pub unsafe fn claim_mut_unsafe<R, TASKPRI, CURRCEIL, F>(
|
||||||
|
// &'static self,
|
||||||
|
// _prio: &P<TASKPRI>,
|
||||||
|
// _curr_ceil: &C<CURRCEIL>,
|
||||||
|
// f: F,
|
||||||
|
// ) -> R
|
||||||
|
// where
|
||||||
|
// F: FnOnce(&mut T, &C<<CEILING as Max<CURRCEIL>>::Output>) -> R,
|
||||||
|
// TASKPRI: Unsigned,
|
||||||
|
// CURRCEIL: Unsigned,
|
||||||
|
// CEILING: GreaterThanOrEqual<TASKPRI> + Max<CURRCEIL> + Level + Unsigned,
|
||||||
|
// {
|
||||||
|
//
|
||||||
|
// let curr_ceil = <CURRCEIL>::to_u8();
|
||||||
|
// let new_ceil = <CEILING>::to_u8();
|
||||||
|
// if new_ceil > curr_ceil {
|
||||||
|
// let old_basepri = basepri::read();
|
||||||
|
// basepri_max::write(<CEILING>::hw());
|
||||||
|
// barrier!();
|
||||||
|
//
|
||||||
|
// let ret = f(&mut *self.data.get(), &C { _marker: PhantomData });
|
||||||
|
//
|
||||||
|
// barrier!();
|
||||||
|
// basepri::write(old_basepri);
|
||||||
|
// ret
|
||||||
|
// } else {
|
||||||
|
//
|
||||||
|
// let ret = f(&mut *self.data.get(), &C { _marker: PhantomData });
|
||||||
|
//
|
||||||
|
// ret
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// // / Locks the resource for the duration of the critical section `f`
|
||||||
|
// // /
|
||||||
|
// // / For the duration of the critical section, tasks whose priority level is
|
||||||
|
// // / smaller than or equal to the resource `CEILING` will be prevented from
|
||||||
|
// // / preempting the current task.
|
||||||
|
// // /
|
||||||
|
// // / Within this critical section, resources with ceiling equal to or smaller
|
||||||
|
// // / than `CEILING` can be borrowed at zero cost. See
|
||||||
|
// // / [Resource.borrow](struct.Resource.html#method.borrow).
|
||||||
|
// // #[cfg(not(thumbv6m))]
|
||||||
|
// // pub fn claim_mut<R, PRIOTASK, CURRCEIL, F>(
|
||||||
|
// // &'static self,
|
||||||
|
// // _prio: &P<PRIOTASK>,
|
||||||
|
// // _curr_ceil: &C<CURRCEIL>,
|
||||||
|
// // f: F,
|
||||||
|
// // ) -> R
|
||||||
|
// // where
|
||||||
|
// // F: FnOnce(&mut T, &C<<CEILING as Max<CURRCEIL>>::Output>) -> R,
|
||||||
|
// // PRIOTASK: Unsigned,
|
||||||
|
// // CURRCEIL: Unsigned,
|
||||||
|
// // CEILING: GreaterThanOrEqual<PRIOTASK> + Max<CURRCEIL> + Level + Unsigned,
|
||||||
|
// // {
|
||||||
|
// // unsafe {
|
||||||
|
// // match self._state.get() {
|
||||||
|
// // State::Free => {
|
||||||
|
// // let c1 = <CURRCEIL>::to_u8();
|
||||||
|
// // let c2 = <CEILING>::to_u8();
|
||||||
|
// // if c2 > c1 {
|
||||||
|
// // let old_basepri = basepri::read();
|
||||||
|
// // basepri_max::write(<CEILING>::hw());
|
||||||
|
// // barrier!();
|
||||||
|
// // self._state.set(State::LockedMut);
|
||||||
|
// // barrier!();
|
||||||
|
// //
|
||||||
|
// // let ret = f(
|
||||||
|
// // &mut *self.data.get(),
|
||||||
|
// // &C { _marker: PhantomData },
|
||||||
|
// // );
|
||||||
|
// //
|
||||||
|
// // barrier!();
|
||||||
|
// // self._state.set(State::Free);
|
||||||
|
// // barrier!();
|
||||||
|
// // basepri::write(old_basepri);
|
||||||
|
// // ret
|
||||||
|
// // } else {
|
||||||
|
// // self._state.set(State::LockedMut);
|
||||||
|
// // barrier!();
|
||||||
|
// //
|
||||||
|
// // let ret = f(
|
||||||
|
// // &mut *self.data.get(),
|
||||||
|
// // &C { _marker: PhantomData },
|
||||||
|
// // );
|
||||||
|
// //
|
||||||
|
// // barrier!();
|
||||||
|
// // self._state.set(State::Free);
|
||||||
|
// // ret
|
||||||
|
// //
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // _ => panic!("Resource already locked)"),
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
unsafe impl<T, C> Sync for ResRef<T, C>
|
||||||
where
|
where
|
||||||
C: Ceiling,
|
C: Ceiling,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
/// A hardware peripheral as a resource
|
/// A hardware peripheral as a resource
|
||||||
pub struct Peripheral<P, CEILING>
|
pub struct Peripheral<P, CEILING>
|
||||||
where
|
where
|
||||||
|
|
Loading…
Reference in a new issue