aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar pln <Per Lindgren> 2017-04-21 01:51:10 +0200
committerGravatar pln <Per Lindgren> 2017-04-21 01:51:10 +0200
commit9ede9215c27c12bec08dc96023ab9c1d0509057e (patch)
treee79eafa5d97339aae8ba3c9961f427f565336894
parent8e0569c396ddfba2c6195f9e72d674956ac0f51f (diff)
downloadrtic-9ede9215c27c12bec08dc96023ab9c1d0509057e.tar.gz
rtic-9ede9215c27c12bec08dc96023ab9c1d0509057e.tar.zst
rtic-9ede9215c27c12bec08dc96023ab9c1d0509057e.zip
failed attempt at new claim
-rw-r--r--src/lib.rs438
1 files changed, 266 insertions, 172 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 17070825..e9b1a24c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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