2019-11-18 09:13:54 +08:00
use core ::ops ::{ Deref , DerefMut } ;
2019-11-18 09:37:59 +08:00
use core ::sync ::atomic ::{ AtomicU32 , Ordering } ;
2019-11-18 09:13:54 +08:00
use core ::cell ::UnsafeCell ;
use super ::asm ::* ;
2019-11-20 23:19:35 +08:00
/// [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 ( ) ;
}
2019-11-18 09:37:59 +08:00
const LOCKED : u32 = 1 ;
const UNLOCKED : u32 = 0 ;
2019-11-18 09:13:54 +08:00
2019-11-20 23:19:35 +08:00
/// 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)
2019-11-18 09:13:54 +08:00
pub struct Mutex < T > {
2019-11-18 09:37:59 +08:00
locked : AtomicU32 ,
2019-11-18 09:13:54 +08:00
inner : UnsafeCell < T > ,
}
unsafe impl < T : Send > Sync for Mutex < T > { }
unsafe impl < T : Send > Send for Mutex < T > { }
impl < T > Mutex < T > {
2019-11-20 23:19:35 +08:00
/// Constructor, const-fn
2019-11-18 09:13:54 +08:00
pub const fn new ( inner : T ) -> Self {
Mutex {
2019-11-18 09:37:59 +08:00
locked : AtomicU32 ::new ( UNLOCKED ) ,
2019-11-18 09:13:54 +08:00
inner : UnsafeCell ::new ( inner ) ,
}
}
2019-11-20 23:19:35 +08:00
/// Lock the Mutex, blocks when already locked
2019-11-18 09:13:54 +08:00
pub fn lock ( & self ) -> MutexGuard < T > {
2019-11-20 23:19:35 +08:00
while self . locked . compare_and_swap ( UNLOCKED , LOCKED , Ordering ::Acquire ) ! = UNLOCKED {
wait_for_update ( ) ;
}
2019-11-18 09:13:54 +08:00
dmb ( ) ;
MutexGuard { mutex : self }
}
2020-07-15 16:41:28 +08:00
pub fn try_lock ( & self ) -> Option < MutexGuard < T > > {
if self . locked . compare_and_swap ( UNLOCKED , LOCKED , Ordering ::Acquire ) ! = UNLOCKED {
None
} else {
dmb ( ) ;
Some ( MutexGuard { mutex : self } )
}
}
2019-11-18 09:13:54 +08:00
fn unlock ( & self ) {
dmb ( ) ;
2019-11-18 09:37:59 +08:00
self . locked . store ( UNLOCKED , Ordering ::Release ) ;
2019-11-20 23:19:35 +08:00
signal_update ( ) ;
2019-11-18 09:13:54 +08:00
}
}
2019-11-20 23:19:35 +08:00
/// Returned by `Mutex.lock()`, allows access to data via
/// `Deref`/`DerefMutx`
2019-11-18 09:13:54 +08:00
pub struct MutexGuard < ' a , T > {
mutex : & ' a Mutex < T > ,
}
impl < ' a , T > Deref for MutexGuard < ' a , T > {
type Target = T ;
fn deref ( & self ) -> & T {
unsafe { & * self . mutex . inner . get ( ) }
}
}
impl < ' a , T > DerefMut for MutexGuard < ' a , T > {
fn deref_mut ( & mut self ) -> & mut T {
unsafe { & mut * self . mutex . inner . get ( ) }
}
}
2019-11-20 23:19:35 +08:00
/// Automatically `Mutex.unlock()` when this reference is dropped
2019-11-18 09:13:54 +08:00
impl < ' a , T > Drop for MutexGuard < ' a , T > {
fn drop ( & mut self ) {
self . mutex . unlock ( ) ;
}
}