cortex_a9::mutex: restore and fix powersaving behaviour, doc

This commit is contained in:
Astro 2019-11-20 16:19:35 +01:00
parent d89f594ba4
commit ff41f4dd2d
1 changed files with 27 additions and 3 deletions

View File

@ -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();