diff options
| author | Jorge Aparicio <japaricious@gmail.com> | 2017-04-07 17:34:06 -0500 |
|---|---|---|
| committer | Jorge Aparicio <japaricious@gmail.com> | 2017-04-07 17:34:06 -0500 |
| commit | 2ae638995c7b03db9a145197cf3a5d0c6d5fe20c (patch) | |
| tree | 09dc7c3f3cbfe34a873b88ae58e19af21899dc8e | |
| parent | 759ac160db3a02d23b1126c6875143b67f5c2e20 (diff) | |
initial version of checked resources
| -rw-r--r-- | src/checked.rs | 77 | ||||
| -rw-r--r-- | src/lib.rs | 2 |
2 files changed, 79 insertions, 0 deletions
diff --git a/src/checked.rs b/src/checked.rs new file mode 100644 index 0000000..836890d --- /dev/null +++ b/src/checked.rs @@ -0,0 +1,77 @@ +//! Safe, run-time checked resources + +use core::marker::PhantomData; +use core::cell::UnsafeCell; + +use cortex_m::interrupt; +use cortex_m::register::{basepri, basepri_max}; + +use Ceiling; + +unsafe fn acquire(locked: &UnsafeCell<bool>, ceiling: u8) -> u8 { + interrupt::free( + |_| { + assert!(!*locked.get(), "resource already locked"); + let old_basepri = basepri::read(); + basepri_max::write(ceiling); + *locked.get() = true; + old_basepri + }, + ) +} + +unsafe fn release(locked: &UnsafeCell<bool>, old_basepri: u8) { + interrupt::free( + |_| { + basepri::write(old_basepri); + *locked.get() = false; + }, + ); +} + +/// A totally safe `Resource` that panics on misuse +pub struct Resource<T, C> { + _marker: PhantomData<C>, + data: UnsafeCell<T>, + locked: UnsafeCell<bool>, +} + +impl<T, C> Resource<T, C> +where + C: Ceiling, +{ + /// Creates a new `Resource` with ceiling `C` + pub const fn new(data: T) -> Resource<T, C> { + Resource { + _marker: PhantomData, + data: UnsafeCell::new(data), + locked: UnsafeCell::new(false), + } + } + + /// Locks the resource, blocking tasks with priority equal or smaller than + /// the ceiling `C` + pub fn lock<F>(&'static self, f: F) + where + F: FnOnce(&T), + { + unsafe { + let old_basepri = acquire(&self.locked, C::ceiling()); + f(&*self.data.get()); + release(&self.locked, old_basepri); + } + } + + /// Mutably locks the resource, blocking tasks with priority equal or + /// smaller than the ceiling `C` + pub fn lock_mut<F>(&'static self, f: F) + where + F: FnOnce(&mut T), + { + unsafe { + let old_basepri = acquire(&self.locked, C::ceiling()); + f(&mut *self.data.get()); + release(&self.locked, old_basepri); + } + } +} @@ -10,6 +10,8 @@ extern crate cortex_m; +pub mod checked; + use cortex_m::ctxt::Context; use cortex_m::interrupt::{CriticalSection, Nr}; use cortex_m::peripheral::{Peripheral, NVIC}; |
