use super::wait_queue::WaitQueue;
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicIsize, Ordering};
use std::task::{Context, Poll};
const WRITE_LOCKED: isize = -1;
#[repr(align(64))]
pub struct RwLock<T: ?Sized> {
state: AtomicIsize,
wait: WaitQueue,
data: UnsafeCell<T>,
}
unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
impl<T> RwLock<T> {
#[must_use]
pub const fn new(data: T) -> Self {
Self {
state: AtomicIsize::new(0),
wait: WaitQueue::new(),
data: UnsafeCell::new(data),
}
}
#[inline(always)]
pub fn into_inner(self) -> T {
self.data.into_inner()
}
}
impl<T: ?Sized + Send + Sync> RwLock<T> {
#[inline(always)]
pub async fn read(&self) -> RwLockReadGuard<'_, T> {
std::future::poll_fn(|cx| self.poll_read(cx)).await
}
#[inline(always)]
pub async fn write(&self) -> RwLockWriteGuard<'_, T> {
std::future::poll_fn(|cx| self.poll_write(cx)).await
}
}
impl<T: ?Sized> RwLock<T> {
#[must_use]
#[inline(always)]
pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T>> {
self.try_acquire_read()
.then(|| RwLockReadGuard { lock: self })
}
#[must_use]
#[inline(always)]
pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T>> {
self.state
.compare_exchange(0, WRITE_LOCKED, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
.then(|| RwLockWriteGuard { lock: self })
}
#[inline(always)]
fn try_acquire_read(&self) -> bool {
let mut current = self.state.load(Ordering::Relaxed);
loop {
if current < 0 {
return false;
}
match self.state.compare_exchange_weak(
current,
current + 1,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => return true,
Err(observed) => current = observed,
}
}
}
#[inline(always)]
fn poll_read(&self, cx: &Context<'_>) -> Poll<RwLockReadGuard<'_, T>> {
if self.try_acquire_read() {
return Poll::Ready(RwLockReadGuard { lock: self });
}
let token = self.wait.register(cx.waker());
if self.try_acquire_read() {
self.wait.cancel(token);
return Poll::Ready(RwLockReadGuard { lock: self });
}
Poll::Pending
}
#[inline(always)]
fn poll_write(&self, cx: &Context<'_>) -> Poll<RwLockWriteGuard<'_, T>> {
if !self.wait.has_waiters()
&& let Some(guard) = self.try_write()
{
return Poll::Ready(guard);
}
let token = self.wait.register(cx.waker());
if let Some(guard) = self.try_write() {
self.wait.cancel(token);
return Poll::Ready(guard);
}
Poll::Pending
}
pub const fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
}
impl<T: Default> Default for RwLock<T> {
fn default() -> Self {
Self {
state: AtomicIsize::new(0),
wait: WaitQueue::new(),
data: UnsafeCell::new(T::default()),
}
}
}
#[repr(align(64))]
pub struct RwLockReadGuard<'a, T: ?Sized> {
lock: &'a RwLock<T>,
}
unsafe impl<T: ?Sized + Sync> Send for RwLockReadGuard<'_, T> {}
unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
#[inline(always)]
fn drop(&mut self) {
let prev = self.lock.state.fetch_sub(1, Ordering::Release);
if prev == 1 {
self.lock.wait.wake_all();
}
}
}
#[repr(align(64))]
pub struct RwLockWriteGuard<'a, T: ?Sized> {
lock: &'a RwLock<T>,
}
unsafe impl<T: ?Sized + Send> Send for RwLockWriteGuard<'_, T> {}
unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {}
impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.data.get() }
}
}
impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
#[inline(always)]
fn drop(&mut self) {
self.lock.state.store(0, Ordering::Release);
self.lock.wait.wake_all();
}
}