This crate provides PinList
, a safe Pin
-based intrusive doubly linked list.
A thread-safe unfair async mutex.
```rust use pinprojectlite::pinproject; use std::cell::UnsafeCell; use std::future::Future; use std::ops::Deref; use std::ops::DerefMut; use std::pin::Pin; use std::task; use std::task::Poll; use pinlist::PinList;
type PinListTypes = dyn pinlist::Types< Id = pinlist::id::Checked, Protected = task::Waker, Removed = (), Unprotected = (),
;
pub struct Mutex
struct Inner {
locked: bool,
waiters: PinList
unsafe impl
impl
pinproject! {
pub struct Lock<'mutex, T> {
mutex: &'mutex Mutex
impl<T> PinnedDrop for Lock<'_, T> {
fn drop(this: Pin<&mut Self>) {
let this = this.project();
let node = match this.node.initialized_mut() {
// The future was cancelled before it could complete.
Some(initialized) => initialized,
// The future has completed already (or hasn't started); we don't have to do
// anything.
None => return,
};
let mut inner = this.mutex.inner.lock().unwrap();
match node.reset(&mut inner.waiters) {
// If we've cancelled the future like usual, just do that.
(pin_list::NodeData::Linked(_waker), ()) => {}
// Otherwise, we have been woken but aren't around to take the lock. To
// prevent deadlocks, pass the notification on to someone else.
(pin_list::NodeData::Removed(()), ()) => {
if let Ok(waker) = inner.waiters.cursor_front_mut().remove_current(()) {
drop(inner);
waker.wake();
}
}
}
}
}
}
impl<'mutex, T> Future for Lock<'mutex, T> {
type Output = Guard<'mutex, T>;
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll
let mut inner = this.mutex.inner.lock().unwrap();
if let Some(mut node) = this.node.as_mut().initialized_mut() {
// Check whether we've been woken up, only continuing if so.
if let Err(node) = node.take_removed(&inner.waiters) {
// If we haven't been woken, re-register our waker and pend.
*node.protected_mut(&mut inner.waiters).unwrap() = cx.waker().clone();
return Poll::Pending;
}
}
// If the mutex is unlocked, mark it as locked and return the guard
if !inner.locked {
inner.locked = true;
return Poll::Ready(Guard { mutex: this.mutex });
}
// Otherwise, re-register ourselves to be woken when the mutex is unlocked again
inner.waiters.push_back(this.node, cx.waker().clone(), ());
Poll::Pending
}
}
pub struct Guard<'mutex, T> {
mutex: &'mutex Mutex
impl
impl
if let Ok(waker) = inner.waiters.cursor_front_mut().remove_current(()) {
drop(inner);
waker.wake();
}
}
} # ```
License: MIT