diff --git a/src/lib.rs b/src/lib.rs index 06efd5114e..91f3a54cd1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ extern crate cortex_m; extern crate static_ref; extern crate typenum; -use core::cell::UnsafeCell; +use core::cell::{Cell, UnsafeCell}; use core::marker::PhantomData; use cortex_m::ctxt::Context; @@ -28,6 +28,8 @@ pub use cortex_m::asm::{bkpt, wfi}; #[doc(hidden)] pub use cortex_m::peripheral::NVIC; +use typenum::type_operators::*; + macro_rules! barrier { () => { asm!("" @@ -57,6 +59,36 @@ impl Resource { } } +#[derive(Copy, Clone)] +enum State { + Free, + // Locked, + LockedMut, +} + +/// A resource +pub struct Res { + _ceiling: PhantomData, + _state: Cell, + //_state: State, + data: UnsafeCell, +} + +impl Res { + /// Creates a new resource with ceiling `C` + pub const fn new(data: T) -> Self + where + C: Ceiling, + { + Res { + _ceiling: PhantomData, + _state: Cell::new(State::Free), + // _state: State::Free, + data: UnsafeCell::new(data), + } + } +} + impl Resource> { /// Borrows the resource for the duration of another resource's critical /// section @@ -99,6 +131,88 @@ impl Resource> { 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 mock( + &'static self, + _prio: &P, + _curr_ceil: &C, + f: F, + ) -> R + where + F: FnOnce(Ref, &C<>::Output>) -> R, + PRIOTASK: Unsigned, + CURRCEIL: Unsigned, + CEILING: GreaterThanOrEqual + Max + Level + Unsigned, + { + unsafe { + let c1 = ::to_u8(); + let c2 = ::to_u8(); + if c2 > c1 { + let old_basepri = basepri::read(); + basepri_max::write(::hw()); + barrier!(); + let ret = + f(Ref::new(&*self.data.get()), &C { _marker: PhantomData }); + barrier!(); + basepri::write(old_basepri); + ret + } else { + f(Ref::new(&*self.data.get()), &C { _marker: PhantomData }) + + } + } + } + + /// 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( + &'static self, + _prio: &P, + _curr_ceil: &C, + f: F, + ) -> R + where + F: FnOnce(Ref, &C<>::Output>) -> R, + PRIOTASK: Unsigned, + CURRCEIL: Unsigned, + CEILING: GreaterThanOrEqual + Max + Level + Unsigned, + { + unsafe { + let c1 = ::to_u8(); + let c2 = ::to_u8(); + if c2 > c1 { + let old_basepri = basepri::read(); + basepri_max::write(::hw()); + barrier!(); + let ret = + f(Ref::new(&*self.data.get()), &C { _marker: PhantomData }); + barrier!(); + basepri::write(old_basepri); + ret + } else { + f(Ref::new(&*self.data.get()), &C { _marker: PhantomData }) + + } + } + } } unsafe impl Sync for Resource @@ -107,6 +221,142 @@ where { } +// re-implementation of the original claim API +impl Res> { + /// 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( + &'static self, + _prio: &P, + _curr_ceil: &C, + f: F, + ) -> R + where + F: FnOnce(Ref, &C<>::Output>) -> R, + PRIOTASK: Unsigned, + CURRCEIL: Unsigned, + CEILING: GreaterThanOrEqual + Max + Level + Unsigned, + { + + match self._state.get() { + State::LockedMut => panic!("Resource already locked)"), + _ => unsafe { + let c1 = ::to_u8(); + let c2 = ::to_u8(); + if c2 > c1 { + let old_basepri = basepri::read(); + basepri_max::write(::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 + } + }, + } + } + /// 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( + &'static self, + _prio: &P, + _curr_ceil: &C, + f: F, + ) -> R + where + F: FnOnce(&mut T, &C<>::Output>) -> R, + PRIOTASK: Unsigned, + CURRCEIL: Unsigned, + CEILING: GreaterThanOrEqual + Max + Level + Unsigned, + { + unsafe { + match self._state.get() { + State::Free => { + let c1 = ::to_u8(); + let c2 = ::to_u8(); + if c2 > c1 { + let old_basepri = basepri::read(); + basepri_max::write(::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 Sync for Res +where + C: Ceiling, +{ +} + /// A hardware peripheral as a resource pub struct Peripheral where @@ -223,6 +473,7 @@ where nvic.set_pending(task); } + /// A type-level ceiling pub struct C { _marker: PhantomData,