failed attempt at new claim

This commit is contained in:
pln 2017-04-21 01:51:10 +02:00
parent 8e0569c396
commit 9ede9215c2

View file

@ -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