forked from M-Labs/zynq-rs
1
0
Fork 0

libcortex_a9/mutex: added interrupt critical section mask.

This commit is contained in:
pca006132 2020-08-03 11:24:18 +08:00 committed by Gitea
parent 8f0a6bd5ea
commit 12669124a4
2 changed files with 38 additions and 3 deletions

View File

@ -40,6 +40,32 @@ pub unsafe fn enable_irq() {
llvm_asm!("cpsie i":::: "volatile"); llvm_asm!("cpsie i":::: "volatile");
} }
/// Disable IRQ, return if IRQ was originally enabled.
#[inline]
pub unsafe fn enter_critical() -> bool {
let mut cpsr: u32;
llvm_asm!(
"mrs $0, cpsr
cpsid i"
: "=r"(cpsr) ::: "volatile");
(cpsr & (1 << 7)) == 0
}
#[inline]
pub unsafe fn exit_critical(enable: bool) {
// https://stackoverflow.com/questions/40019929/temporarily-disable-interrupts-on-arm
let mask: u32 = if enable {
1 << 7
} else {
0
};
llvm_asm!(
"mrs r1, cpsr
bic r1, r1, $0
msr cpsr_c, r1"
:: "r"(mask) : "r1");
}
/// Exiting IRQ /// Exiting IRQ
#[inline] #[inline]
pub unsafe fn exit_irq() { pub unsafe fn exit_irq() {

View File

@ -41,19 +41,26 @@ impl<T> Mutex<T> {
/// Lock the Mutex, blocks when already locked /// Lock the Mutex, blocks when already locked
pub fn lock(&self) -> MutexGuard<T> { pub fn lock(&self) -> MutexGuard<T> {
let mut irq = unsafe { enter_critical() };
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(); unsafe {
exit_critical(irq);
wait_for_update();
irq = enter_critical();
}
} }
dmb(); dmb();
MutexGuard { mutex: self } MutexGuard { mutex: self, irq }
} }
pub fn try_lock(&self) -> Option<MutexGuard<T>> { pub fn try_lock(&self) -> Option<MutexGuard<T>> {
let irq = unsafe { enter_critical() };
if self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED { if self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {
unsafe { exit_critical(irq) };
None None
} else { } else {
dmb(); dmb();
Some(MutexGuard { mutex: self }) Some(MutexGuard { mutex: self, irq })
} }
} }
@ -69,6 +76,7 @@ impl<T> Mutex<T> {
/// `Deref`/`DerefMutx` /// `Deref`/`DerefMutx`
pub struct MutexGuard<'a, T> { pub struct MutexGuard<'a, T> {
mutex: &'a Mutex<T>, mutex: &'a Mutex<T>,
irq: bool,
} }
impl<'a, T> Deref for MutexGuard<'a, T> { impl<'a, T> Deref for MutexGuard<'a, T> {
@ -88,5 +96,6 @@ impl<'a, T> DerefMut for MutexGuard<'a, T> {
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();
unsafe { exit_critical(self.irq) };
} }
} }