use crate::{
intrusive_double_linked_list::{LinkedList, ListNode},
utils::update_waker_ref,
NoopLock,
};
use core::{
cell::UnsafeCell,
ops::{Deref, DerefMut},
pin::Pin,
};
use futures_core::{
future::{FusedFuture, Future},
task::{Context, Poll, Waker},
};
use lock_api::{Mutex as LockApiMutex, RawMutex};
#[derive(PartialEq)]
enum PollState {
New,
Waiting,
Notified,
Done,
}
struct WaitQueueEntry {
task: Option<Waker>,
state: PollState,
}
impl WaitQueueEntry {
fn new() -> WaitQueueEntry {
WaitQueueEntry {
task: None,
state: PollState::New,
}
}
}
struct MutexState {
is_fair: bool,
is_locked: bool,
waiters: LinkedList<WaitQueueEntry>,
}
impl MutexState {
fn new(is_fair: bool) -> Self {
MutexState {
is_fair,
is_locked: false,
waiters: LinkedList::new(),
}
}
fn return_last_waiter(&mut self) -> Option<Waker> {
let last_waiter = if self.is_fair {
self.waiters.peek_last_mut()
} else {
self.waiters.remove_last()
};
if let Some(last_waiter) = last_waiter {
last_waiter.state = PollState::Notified;
let task = &mut last_waiter.task;
return task.take();
}
None
}
fn is_locked(&self) -> bool {
self.is_locked
}
fn unlock(&mut self) -> Option<Waker> {
if self.is_locked {
self.is_locked = false;
self.return_last_waiter()
} else {
None
}
}
fn try_lock_sync(&mut self) -> bool {
if !self.is_locked && (!self.is_fair || self.waiters.is_empty()) {
self.is_locked = true;
true
} else {
false
}
}
unsafe fn try_lock(
&mut self,
wait_node: &mut ListNode<WaitQueueEntry>,
cx: &mut Context<'_>,
) -> Poll<()> {
match wait_node.state {
PollState::New => {
if self.try_lock_sync() {
wait_node.state = PollState::Done;
Poll::Ready(())
} else {
wait_node.task = Some(cx.waker().clone());
wait_node.state = PollState::Waiting;
self.waiters.add_front(wait_node);
Poll::Pending
}
}
PollState::Waiting => {
if self.is_fair {
update_waker_ref(&mut wait_node.task, cx);
Poll::Pending
} else {
if !self.is_locked {
self.is_locked = true;
wait_node.state = PollState::Done;
self.force_remove_waiter(wait_node);
Poll::Ready(())
} else {
update_waker_ref(&mut wait_node.task, cx);
Poll::Pending
}
}
}
PollState::Notified => {
if !self.is_locked {
if self.is_fair {
self.force_remove_waiter(wait_node);
}
self.is_locked = true;
wait_node.state = PollState::Done;
Poll::Ready(())
} else {
debug_assert!(!self.is_fair);
wait_node.task = Some(cx.waker().clone());
wait_node.state = PollState::Waiting;
self.waiters.add_front(wait_node);
Poll::Pending
}
}
PollState::Done => {
panic!("polled Mutex after completion");
}
}
}
unsafe fn force_remove_waiter(
&mut self,
wait_node: &mut ListNode<WaitQueueEntry>,
) {
if !self.waiters.remove(wait_node) {
panic!("Future could not be removed from wait queue");
}
}
fn remove_waiter(
&mut self,
wait_node: &mut ListNode<WaitQueueEntry>,
) -> Option<Waker> {
match wait_node.state {
PollState::Notified => {
if self.is_fair {
unsafe { self.force_remove_waiter(wait_node) };
}
wait_node.state = PollState::Done;
self.return_last_waiter()
}
PollState::Waiting => {
unsafe { self.force_remove_waiter(wait_node) };
wait_node.state = PollState::Done;
None
}
PollState::New | PollState::Done => None,
}
}
}
pub struct GenericMutexGuard<'a, MutexType: RawMutex, T: 'a> {
mutex: &'a GenericMutex<MutexType, T>,
}
impl<MutexType: RawMutex, T: core::fmt::Debug> core::fmt::Debug
for GenericMutexGuard<'_, MutexType, T>
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("GenericMutexGuard").finish()
}
}
impl<MutexType: RawMutex, T> Drop for GenericMutexGuard<'_, MutexType, T> {
fn drop(&mut self) {
let waker = { self.mutex.state.lock().unlock() };
if let Some(waker) = waker {
waker.wake();
}
}
}
impl<MutexType: RawMutex, T> Deref for GenericMutexGuard<'_, MutexType, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.mutex.value.get() }
}
}
impl<MutexType: RawMutex, T> DerefMut for GenericMutexGuard<'_, MutexType, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.mutex.value.get() }
}
}
unsafe impl<MutexType: RawMutex, T: Sync> Sync
for GenericMutexGuard<'_, MutexType, T>
{
}
#[must_use = "futures do nothing unless polled"]
pub struct GenericMutexLockFuture<'a, MutexType: RawMutex, T: 'a> {
mutex: Option<&'a GenericMutex<MutexType, T>>,
wait_node: ListNode<WaitQueueEntry>,
}
unsafe impl<'a, MutexType: RawMutex + Sync, T: 'a> Send
for GenericMutexLockFuture<'a, MutexType, T>
{
}
impl<'a, MutexType: RawMutex, T: core::fmt::Debug> core::fmt::Debug
for GenericMutexLockFuture<'a, MutexType, T>
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("GenericMutexLockFuture").finish()
}
}
impl<'a, MutexType: RawMutex, T> Future
for GenericMutexLockFuture<'a, MutexType, T>
{
type Output = GenericMutexGuard<'a, MutexType, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut_self: &mut GenericMutexLockFuture<MutexType, T> =
unsafe { Pin::get_unchecked_mut(self) };
let mutex = mut_self
.mutex
.expect("polled GenericMutexLockFuture after completion");
let mut mutex_state = mutex.state.lock();
let poll_res =
unsafe { mutex_state.try_lock(&mut mut_self.wait_node, cx) };
match poll_res {
Poll::Pending => Poll::Pending,
Poll::Ready(()) => {
mut_self.mutex = None;
Poll::Ready(GenericMutexGuard::<'a, MutexType, T> { mutex })
}
}
}
}
impl<'a, MutexType: RawMutex, T> FusedFuture
for GenericMutexLockFuture<'a, MutexType, T>
{
fn is_terminated(&self) -> bool {
self.mutex.is_none()
}
}
impl<'a, MutexType: RawMutex, T> Drop
for GenericMutexLockFuture<'a, MutexType, T>
{
fn drop(&mut self) {
let waker = if let Some(mutex) = self.mutex {
let mut mutex_state = mutex.state.lock();
mutex_state.remove_waiter(&mut self.wait_node)
} else {
None
};
if let Some(waker) = waker {
waker.wake();
}
}
}
pub struct GenericMutex<MutexType: RawMutex, T> {
value: UnsafeCell<T>,
state: LockApiMutex<MutexType, MutexState>,
}
unsafe impl<T: Send, MutexType: RawMutex + Send> Send
for GenericMutex<MutexType, T>
{
}
unsafe impl<T: Send, MutexType: RawMutex + Sync> Sync
for GenericMutex<MutexType, T>
{
}
impl<MutexType: RawMutex, T: core::fmt::Debug> core::fmt::Debug
for GenericMutex<MutexType, T>
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("Mutex")
.field("is_locked", &self.is_locked())
.finish()
}
}
impl<MutexType: RawMutex, T> GenericMutex<MutexType, T> {
pub fn new(value: T, is_fair: bool) -> GenericMutex<MutexType, T> {
GenericMutex::<MutexType, T> {
value: UnsafeCell::new(value),
state: LockApiMutex::new(MutexState::new(is_fair)),
}
}
pub fn lock(&self) -> GenericMutexLockFuture<'_, MutexType, T> {
GenericMutexLockFuture::<MutexType, T> {
mutex: Some(&self),
wait_node: ListNode::new(WaitQueueEntry::new()),
}
}
pub fn try_lock(&self) -> Option<GenericMutexGuard<'_, MutexType, T>> {
if self.state.lock().try_lock_sync() {
Some(GenericMutexGuard { mutex: self })
} else {
None
}
}
pub fn is_locked(&self) -> bool {
self.state.lock().is_locked()
}
}
pub type LocalMutex<T> = GenericMutex<NoopLock, T>;
pub type LocalMutexGuard<'a, T> = GenericMutexGuard<'a, NoopLock, T>;
pub type LocalMutexLockFuture<'a, T> = GenericMutexLockFuture<'a, NoopLock, T>;
#[cfg(feature = "std")]
mod if_std {
use super::*;
pub type Mutex<T> = GenericMutex<parking_lot::RawMutex, T>;
pub type MutexGuard<'a, T> =
GenericMutexGuard<'a, parking_lot::RawMutex, T>;
pub type MutexLockFuture<'a, T> =
GenericMutexLockFuture<'a, parking_lot::RawMutex, T>;
}
#[cfg(feature = "std")]
pub use self::if_std::*;