diff options
author | 2017-04-21 01:51:10 +0200 | |
---|---|---|
committer | 2017-04-21 01:51:10 +0200 | |
commit | 9ede9215c27c12bec08dc96023ab9c1d0509057e (patch) | |
tree | e79eafa5d97339aae8ba3c9961f427f565336894 | |
parent | 8e0569c396ddfba2c6195f9e72d674956ac0f51f (diff) | |
download | rtic-9ede9215c27c12bec08dc96023ab9c1d0509057e.tar.gz rtic-9ede9215c27c12bec08dc96023ab9c1d0509057e.tar.zst rtic-9ede9215c27c12bec08dc96023ab9c1d0509057e.zip |
failed attempt at new claim
-rw-r--r-- | src/lib.rs | 438 |
1 files changed, 266 insertions, 172 deletions
@@ -423,71 +423,6 @@ impl<T, CEILING> Res<T, C<CEILING>> { 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> @@ -496,145 +431,304 @@ where { } -/* -// re-implementation of the original claim API -impl<T, CEILING> Res<T, C<CEILING>> { - /// 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<R, PRIOTASK, CURRCEIL, F>( - &'static self, - _prio: &P<PRIOTASK>, - _curr_ceil: &C<CURRCEIL>, - f: F, - ) -> R - where - F: FnOnce(Ref<T>, &C<<CEILING as Max<CURRCEIL>>::Output>) -> R, - PRIOTASK: Unsigned, - CURRCEIL: Unsigned, - CEILING: GreaterThanOrEqual<PRIOTASK> + Max<CURRCEIL> + Level + Unsigned, - { - - match self._state.get() { - State::LockedMut => panic!("Resource already locked)"), - _ => 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!(); +/// Nem attempt +use core::cell::RefCell; +use core::cell::RefMut; - let ret = f( - Ref::new(&*self.data.get()), - &C { _marker: PhantomData }, - ); +//use core::borrow::BorrowMut; +/// A resource +pub struct ResRef<T, CEILING> { + _ceiling: PhantomData<CEILING>, + data: UnsafeCell<RefCell<T>>, +} - barrier!(); - self._state.set(s); - ret - } - }, +impl<T, C> ResRef<T, C> { + /// Creates a new resource with ceiling `C` + pub const fn new(data: T) -> Self + where + C: Ceiling, + { + ResRef { + _ceiling: PhantomData, + data: UnsafeCell::new(RefCell::new(data)), } } +} + +impl<T, CEILING> ResRef<T, C<CEILING>> { /// 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). + /// claim takes three args of type R, PRIOTASK, CURRCEIL, F + /// R is the Resource to lock (self) + /// 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))] - pub fn claim_mut<R, PRIOTASK, CURRCEIL, F>( + pub fn claim_mut<R, TASKPRI, CURRCEIL, F>( &'static self, - _prio: &P<PRIOTASK>, + _prio: &P<TASKPRI>, _curr_ceil: &C<CURRCEIL>, f: F, ) -> R where F: FnOnce(&mut T, &C<<CEILING as Max<CURRCEIL>>::Output>) -> R, - PRIOTASK: Unsigned, + TASKPRI: Unsigned, CURRCEIL: Unsigned, - CEILING: GreaterThanOrEqual<PRIOTASK> + Max<CURRCEIL> + Level + Unsigned, + CEILING: GreaterThanOrEqual<TASKPRI> + 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 + 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!(); - } - } - _ => panic!("Resource already locked)"), + let r: &RefCell<T> = &*self.data.get(); + let rr: RefCell<T> = *r; + let mut rm: RefMut<T> = rr.borrow_mut(); + let mut t: T = *rm; + let ret = f(&mut t, &C { _marker: PhantomData }); + + barrier!(); + basepri::write(old_basepri); + ret + } else { + panic!(""); } } } } -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 C: Ceiling, { } -*/ + /// A hardware peripheral as a resource pub struct Peripheral<P, CEILING> where |