forked from M-Labs/zynq-rs
cortex_a9::mutex: restore and fix powersaving behaviour, doc
This commit is contained in:
parent
d89f594ba4
commit
ff41f4dd2d
|
@ -3,9 +3,25 @@ use core::sync::atomic::{AtomicU32, Ordering};
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use super::asm::*;
|
use super::asm::*;
|
||||||
|
|
||||||
|
/// [Power-saving features](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html)
|
||||||
|
#[inline]
|
||||||
|
fn wait_for_update() {
|
||||||
|
wfe();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [Power-saving features](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html)
|
||||||
|
#[inline]
|
||||||
|
fn signal_update() {
|
||||||
|
dsb();
|
||||||
|
sev();
|
||||||
|
}
|
||||||
|
|
||||||
const LOCKED: u32 = 1;
|
const LOCKED: u32 = 1;
|
||||||
const UNLOCKED: u32 = 0;
|
const UNLOCKED: u32 = 0;
|
||||||
|
|
||||||
|
/// Mutex implementation for Cortex-A9
|
||||||
|
///
|
||||||
|
/// [ARM Synchronization Primitives Development Article: Implementing a mutex](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html)
|
||||||
pub struct Mutex<T> {
|
pub struct Mutex<T> {
|
||||||
locked: AtomicU32,
|
locked: AtomicU32,
|
||||||
inner: UnsafeCell<T>,
|
inner: UnsafeCell<T>,
|
||||||
|
@ -15,15 +31,19 @@ unsafe impl<T: Send> Sync for Mutex<T> {}
|
||||||
unsafe impl<T: Send> Send for Mutex<T> {}
|
unsafe impl<T: Send> Send for Mutex<T> {}
|
||||||
|
|
||||||
impl<T> Mutex<T> {
|
impl<T> Mutex<T> {
|
||||||
|
/// Constructor, const-fn
|
||||||
pub const fn new(inner: T) -> Self {
|
pub const fn new(inner: T) -> Self {
|
||||||
Mutex{
|
Mutex{
|
||||||
locked: AtomicU32::new(UNLOCKED),
|
locked: AtomicU32::new(UNLOCKED),
|
||||||
inner: UnsafeCell::new(inner),
|
inner: UnsafeCell::new(inner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lock the Mutex, blocks when already locked
|
||||||
pub fn lock(&self) -> MutexGuard<T> {
|
pub fn lock(&self) -> MutexGuard<T> {
|
||||||
while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {}
|
while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {
|
||||||
|
wait_for_update();
|
||||||
|
}
|
||||||
dmb();
|
dmb();
|
||||||
MutexGuard { mutex: self }
|
MutexGuard { mutex: self }
|
||||||
}
|
}
|
||||||
|
@ -31,10 +51,13 @@ impl<T> Mutex<T> {
|
||||||
fn unlock(&self) {
|
fn unlock(&self) {
|
||||||
dmb();
|
dmb();
|
||||||
self.locked.store(UNLOCKED, Ordering::Release);
|
self.locked.store(UNLOCKED, Ordering::Release);
|
||||||
dsb();
|
|
||||||
|
signal_update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returned by `Mutex.lock()`, allows access to data via
|
||||||
|
/// `Deref`/`DerefMutx`
|
||||||
pub struct MutexGuard<'a, T> {
|
pub struct MutexGuard<'a, T> {
|
||||||
mutex: &'a Mutex<T>,
|
mutex: &'a Mutex<T>,
|
||||||
}
|
}
|
||||||
|
@ -52,6 +75,7 @@ impl<'a, T> DerefMut for MutexGuard<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Automatically `Mutex.unlock()` when this reference is dropped
|
||||||
impl<'a, T> Drop for MutexGuard<'a, T> {
|
impl<'a, T> Drop for MutexGuard<'a, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.mutex.unlock();
|
self.mutex.unlock();
|
||||||
|
|
Loading…
Reference in New Issue