aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jorge Aparicio <japaricious@gmail.com> 2016-10-30 10:27:06 -0500
committerGravatar Jorge Aparicio <japaricious@gmail.com> 2016-11-19 09:59:00 -0500
commit0b774e9e9850ca483afaf89c09ee2e5841050fa7 (patch)
tree912b250835e40553280d37203b9b214fbec0a138
parent9d97ed3e739dba4c9bff0a4733035a355a91b896 (diff)
downloadcortex-m-0b774e9e9850ca483afaf89c09ee2e5841050fa7.tar.gz
cortex-m-0b774e9e9850ca483afaf89c09ee2e5841050fa7.tar.zst
cortex-m-0b774e9e9850ca483afaf89c09ee2e5841050fa7.zip
add a mutex based on critical sections
-rw-r--r--src/interrupt.rs41
-rw-r--r--src/lib.rs1
2 files changed, 37 insertions, 5 deletions
diff --git a/src/interrupt.rs b/src/interrupt.rs
index 6fb8aeb..4305071 100644
--- a/src/interrupt.rs
+++ b/src/interrupt.rs
@@ -1,5 +1,34 @@
//! Interrupts
+use core::cell::UnsafeCell;
+
+/// A "mutex" based on critical sections
+pub struct Mutex<T> {
+ inner: UnsafeCell<T>,
+}
+
+impl<T> Mutex<T> {
+ /// Creates a new mutex
+ pub const fn new(value: T) -> Self {
+ Mutex { inner: UnsafeCell::new(value) }
+ }
+}
+
+impl<T> Mutex<T> {
+ /// Gets access to the inner data
+ ///
+ /// NOTE this prevents interrupts handlers from running thus gaining
+ /// exclusive access to the processor
+ pub fn lock<F, R>(&self, f: F) -> R
+ where F: FnOnce(&mut T) -> R
+ {
+ unsafe { ::interrupt::free(|| f(&mut *self.inner.get())) }
+ }
+}
+
+// FIXME `T` should have some bound: `Send` or `Sync`?
+unsafe impl<T> Sync for Mutex<T> {}
+
/// Disable interrupts, globally
#[inline(always)]
pub unsafe fn disable() {
@@ -28,20 +57,22 @@ pub unsafe fn enable() {
/// Execute closure `f` in an interrupt-free context.
/// This as also known as a "critical section".
-pub unsafe fn free<F>(f: F)
- where F: FnOnce()
+pub unsafe fn free<F, R>(f: F) -> R
+ where F: FnOnce() -> R
{
let primask = ::register::primask::read();
disable();
- f();
+ let r = f();
- // If the interrupts were enabled before our `disable` call, then re-enable them
- // Otherwise, keep them disabled
+ // If the interrupts were enabled before our `disable` call, then re-enable
+ // them. Otherwise, keep them disabled
// PRIMASK & 1 = 1 indicates that the interrupts were disabled
// PRIMASK & 1 = 0 indicates that they were enabled
if primask & 1 == 0 {
enable();
}
+
+ r
}
diff --git a/src/lib.rs b/src/lib.rs
index 0629191..7459c4e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,6 +12,7 @@
#![deny(missing_docs)]
#![deny(warnings)]
#![feature(asm)]
+#![feature(const_fn)]
#![no_std]
extern crate volatile_register;