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 ;
2022-05-24 16:59:01 +08:00
use core ::task ::{ Context , Poll } ;
use core ::pin ::Pin ;
use core ::future ::Future ;
2020-08-04 13:50:42 +08:00
use super ::{
spin_lock_yield , notify_spin_lock ,
2020-08-24 15:24:20 +08:00
asm ::{ enter_critical , exit_critical }
2020-08-04 13:50:42 +08:00
} ;
2019-11-20 23:19:35 +08:00
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 > { }
2022-05-24 16:59:01 +08:00
struct Fut < ' a , T > ( & ' a Mutex < T > ) ;
impl < ' a , T > Future for Fut < ' a , T > {
type Output = MutexGuard < ' a , T > ;
fn poll ( self : Pin < & mut Self > , cx : & mut Context < '_ > ) -> Poll < Self ::Output > {
let irq = unsafe { enter_critical ( ) } ;
if self . 0. locked . compare_exchange_weak ( UNLOCKED , LOCKED , Ordering ::AcqRel , Ordering ::Relaxed ) . is_err ( ) {
unsafe { exit_critical ( irq ) } ;
cx . waker ( ) . wake_by_ref ( ) ;
Poll ::Pending
}
else {
Poll ::Ready ( MutexGuard { mutex : self . 0 , irq } )
}
}
}
2019-11-18 09:13:54 +08:00
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 > {
2020-08-03 11:24:18 +08:00
let mut irq = unsafe { enter_critical ( ) } ;
2021-01-15 16:43:26 +08:00
while self . locked . compare_exchange_weak ( UNLOCKED , LOCKED , Ordering ::AcqRel , Ordering ::Relaxed ) . is_err ( ) {
2020-08-03 11:24:18 +08:00
unsafe {
exit_critical ( irq ) ;
2020-08-04 13:50:42 +08:00
spin_lock_yield ( ) ;
2020-08-03 11:24:18 +08:00
irq = enter_critical ( ) ;
}
2019-11-20 23:19:35 +08:00
}
2020-08-03 11:24:18 +08:00
MutexGuard { mutex : self , irq }
2019-11-18 09:13:54 +08:00
}
2022-05-24 16:59:01 +08:00
pub async fn async_lock ( & self ) -> MutexGuard < '_ , T > {
Fut ( & self ) . await
}
2020-07-15 16:41:28 +08:00
pub fn try_lock ( & self ) -> Option < MutexGuard < T > > {
2020-08-03 11:24:18 +08:00
let irq = unsafe { enter_critical ( ) } ;
2021-01-15 16:43:26 +08:00
if self . locked . compare_exchange_weak ( UNLOCKED , LOCKED , Ordering ::AcqRel , Ordering ::Relaxed ) . is_err ( ) {
2020-08-03 11:24:18 +08:00
unsafe { exit_critical ( irq ) } ;
2020-07-15 16:41:28 +08:00
None
} else {
2020-08-03 11:24:18 +08:00
Some ( MutexGuard { mutex : self , irq } )
2020-07-15 16:41:28 +08:00
}
}
2019-11-18 09:13:54 +08:00
fn unlock ( & self ) {
2019-11-18 09:37:59 +08:00
self . locked . store ( UNLOCKED , Ordering ::Release ) ;
2019-11-20 23:19:35 +08:00
2020-08-04 13:50:42 +08:00
notify_spin_lock ( ) ;
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 > ,
2020-08-03 11:24:18 +08:00
irq : bool ,
2019-11-18 09:13:54 +08:00
}
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 ( ) ;
2020-08-03 11:24:18 +08:00
unsafe { exit_critical ( self . irq ) } ;
2019-11-18 09:13:54 +08:00
}
}