mutex: add async version of lock

This commit is contained in:
mwojcik 2022-05-24 16:59:01 +08:00
parent 56c27e98e4
commit 605c8f73a6

View File

@ -1,6 +1,9 @@
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use core::sync::atomic::{AtomicU32, Ordering}; use core::sync::atomic::{AtomicU32, Ordering};
use core::cell::UnsafeCell; use core::cell::UnsafeCell;
use core::task::{Context, Poll};
use core::pin::Pin;
use core::future::Future;
use super::{ use super::{
spin_lock_yield, notify_spin_lock, spin_lock_yield, notify_spin_lock,
asm::{enter_critical, exit_critical} asm::{enter_critical, exit_critical}
@ -20,6 +23,23 @@ pub struct Mutex<T> {
unsafe impl<T: Send> Sync for Mutex<T> {} unsafe impl<T: Send> Sync for Mutex<T> {}
unsafe impl<T: Send> Send for Mutex<T> {} unsafe impl<T: Send> Send for Mutex<T> {}
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 })
}
}
}
impl<T> Mutex<T> { impl<T> Mutex<T> {
/// Constructor, const-fn /// Constructor, const-fn
pub const fn new(inner: T) -> Self { pub const fn new(inner: T) -> Self {
@ -42,6 +62,10 @@ impl<T> Mutex<T> {
MutexGuard { mutex: self, irq } MutexGuard { mutex: self, irq }
} }
pub async fn async_lock(&self) -> MutexGuard<'_, T> {
Fut(&self).await
}
pub fn try_lock(&self) -> Option<MutexGuard<T>> { pub fn try_lock(&self) -> Option<MutexGuard<T>> {
let irq = unsafe { enter_critical() }; let irq = unsafe { enter_critical() };
if self.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() { if self.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {