use core::cell::UnsafeCell;
use core::fmt;
use core::ops::{Deref, DerefMut};
use core::sync::atomic::{AtomicU32, Ordering};
use super::GuestUsize;
mod lyquor_api {
use super::GuestUsize;
#[link(wasm_import_module = "lyquor_api")]
unsafe extern "C" {
pub fn __wait(ptr: GuestUsize, exp: u32, timeout: i64, offset: GuestUsize) -> u32;
pub fn __notify(ptr: GuestUsize, cnt: u32, offset: GuestUsize) -> u32;
}
}
const MUTEX_UNLOCKED: u32 = 0;
const MUTEX_LOCKED: u32 = 1;
const MUTEX_CONTENDED: u32 = 2;
#[derive(Debug)]
pub struct Mutex<T: ?Sized> {
state: AtomicU32,
data: UnsafeCell<T>,
}
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
impl<T> Mutex<T> {
pub const fn new(data: T) -> Self {
Self {
state: AtomicU32::new(MUTEX_UNLOCKED),
data: UnsafeCell::new(data),
}
}
}
impl<T: ?Sized> Mutex<T> {
#[inline]
pub fn lock(&self) -> MutexGuard<'_, T> {
if self
.state
.compare_exchange(MUTEX_UNLOCKED, MUTEX_LOCKED, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
self.lock_slow();
}
MutexGuard { lock: self }
}
#[cold]
fn lock_slow(&self) {
let mut s = self.state.load(Ordering::Relaxed);
loop {
if s == MUTEX_UNLOCKED {
match self
.state
.compare_exchange(MUTEX_UNLOCKED, MUTEX_CONTENDED, Ordering::Acquire, Ordering::Relaxed)
{
Ok(_) => return, Err(e) => s = e,
}
continue;
}
if s == MUTEX_LOCKED {
match self
.state
.compare_exchange(MUTEX_LOCKED, MUTEX_CONTENDED, Ordering::Relaxed, Ordering::Relaxed)
{
Ok(_) => s = MUTEX_CONTENDED,
Err(e) => s = e,
}
continue;
}
unsafe {
lyquor_api::__wait(self.state.as_ptr() as GuestUsize, MUTEX_CONTENDED, -1, 0 as GuestUsize);
}
s = self.state.load(Ordering::Relaxed);
}
}
fn unlock(&self) {
let prev = self.state.swap(MUTEX_UNLOCKED, Ordering::Release);
if prev == MUTEX_CONTENDED {
unsafe {
lyquor_api::__notify(self.state.as_ptr() as GuestUsize, 1, 0 as GuestUsize);
}
}
}
}
pub struct MutexGuard<'a, T: ?Sized> {
lock: &'a Mutex<T>,
}
impl<T: ?Sized> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.data.get() }
}
}
impl<T: ?Sized> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
self.lock.unlock();
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
const RWLOCK_WRITER: u32 = u32::MAX;
const RWLOCK_UNLOCKED: u32 = 0;
const RWLOCK_MAX_READERS: u32 = u32::MAX - 2;
#[derive(Debug)]
pub struct RwLock<T: ?Sized> {
state: AtomicU32, writers_waiting: AtomicU32, data: UnsafeCell<T>,
}
unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
unsafe impl<T: ?Sized + Send + Sync> Send for RwLock<T> {}
impl<T> RwLock<T> {
pub const fn new(data: T) -> Self {
Self {
state: AtomicU32::new(RWLOCK_UNLOCKED),
writers_waiting: AtomicU32::new(0),
data: UnsafeCell::new(data),
}
}
}
struct WriterQueueGuard<'a>(&'a AtomicU32);
impl Drop for WriterQueueGuard<'_> {
fn drop(&mut self) {
let prev = self.0.fetch_sub(1, Ordering::AcqRel);
if prev == 1 {
unsafe {
lyquor_api::__notify(self.0.as_ptr() as GuestUsize, u32::MAX, 0 as GuestUsize);
}
}
}
}
impl<T: ?Sized> RwLock<T> {
#[inline]
pub fn read(&self) -> RwLockReadGuard<'_, T> {
loop {
let s = self.state.load(Ordering::Relaxed);
if s == RWLOCK_WRITER {
unsafe {
lyquor_api::__wait(self.state.as_ptr() as GuestUsize, RWLOCK_WRITER, -1, 0 as GuestUsize);
}
continue;
}
let ww = self.writers_waiting.load(Ordering::Acquire);
if ww != 0 {
unsafe {
lyquor_api::__wait(self.writers_waiting.as_ptr() as GuestUsize, ww, -1, 0 as GuestUsize);
}
continue;
}
if s > RWLOCK_MAX_READERS {
unsafe {
lyquor_api::__wait(self.state.as_ptr() as GuestUsize, s, -1, 0 as GuestUsize);
}
continue;
}
match self
.state
.compare_exchange_weak(s, s + 1, Ordering::Acquire, Ordering::Relaxed)
{
Ok(_) => return RwLockReadGuard { lock: self },
Err(_) => continue,
}
}
}
#[inline]
pub fn write(&self) -> RwLockWriteGuard<'_, T> {
self.writers_waiting.fetch_add(1, Ordering::AcqRel);
let _guard = WriterQueueGuard(&self.writers_waiting);
loop {
let s = self.state.load(Ordering::Relaxed);
if s == RWLOCK_UNLOCKED {
if self
.state
.compare_exchange_weak(RWLOCK_UNLOCKED, RWLOCK_WRITER, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
return RwLockWriteGuard { lock: self };
}
} else {
unsafe {
lyquor_api::__wait(self.state.as_ptr() as GuestUsize, s, -1, 0 as GuestUsize);
}
}
}
}
fn unlock_read(&self) {
let prev = self.state.fetch_sub(1, Ordering::Release);
if prev == 1 {
unsafe {
lyquor_api::__notify(self.state.as_ptr() as GuestUsize, 1, 0 as GuestUsize);
}
}
}
fn unlock_write(&self) {
self.state.store(RWLOCK_UNLOCKED, Ordering::Release);
let cnt = if self.writers_waiting.load(Ordering::Acquire) != 0 {
1
} else {
u32::MAX
};
unsafe {
lyquor_api::__notify(self.state.as_ptr() as GuestUsize, cnt, 0 as GuestUsize);
}
}
}
pub struct RwLockReadGuard<'a, T: ?Sized> {
lock: &'a RwLock<T>,
}
impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
fn drop(&mut self) {
self.lock.unlock_read();
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
pub struct RwLockWriteGuard<'a, T: ?Sized> {
lock: &'a RwLock<T>,
}
impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.data.get() }
}
}
impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
fn drop(&mut self) {
self.lock.unlock_write();
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}