aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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;