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;
}
}
pub(crate) mod oneshot {
use core::cell::UnsafeCell;
use core::fmt;
use core::mem::MaybeUninit;
use core::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use super::{GuestUsize, lyquor_api};
const VALUE_READY: u32 = 1 << 0;
const SENDER_CLOSED: u32 = 1 << 1;
const RECEIVER_CLOSED: u32 = 1 << 2;
struct Shared<T> {
state: AtomicU32,
value: UnsafeCell<MaybeUninit<T>>,
}
unsafe impl<T: Send> Sync for Shared<T> {}
impl<T> Shared<T> {
fn new() -> Self {
Self {
state: AtomicU32::new(0),
value: UnsafeCell::new(MaybeUninit::uninit()),
}
}
fn notify_receiver(&self) {
unsafe {
lyquor_api::__notify(self.state.as_ptr() as GuestUsize, 1, 0 as GuestUsize);
}
}
}
impl<T> Drop for Shared<T> {
fn drop(&mut self) {
if *self.state.get_mut() & VALUE_READY != 0 {
unsafe {
self.value.get_mut().assume_init_drop();
}
}
}
}
pub struct Sender<T> {
shared: Option<Arc<Shared<T>>>,
}
impl<T> Sender<T> {
pub fn send(mut self, value: T) -> Result<(), T> {
let shared = self.shared.take().expect("one-shot sender is always initialized");
if shared.state.load(Ordering::Acquire) & RECEIVER_CLOSED != 0 {
return Err(value);
}
unsafe {
(*shared.value.get()).write(value);
}
let previous = shared.state.fetch_or(VALUE_READY | SENDER_CLOSED, Ordering::AcqRel);
if previous & RECEIVER_CLOSED != 0 {
let value = unsafe { (*shared.value.get()).assume_init_read() };
shared.state.fetch_and(!VALUE_READY, Ordering::Relaxed);
return Err(value);
}
shared.notify_receiver();
Ok(())
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
let Some(shared) = self.shared.take() else {
return;
};
shared.state.fetch_or(SENDER_CLOSED, Ordering::Release);
shared.notify_receiver();
}
}
pub struct Receiver<T> {
shared: Option<Arc<Shared<T>>>,
}
impl<T> Receiver<T> {
pub fn recv(mut self) -> Result<T, RecvError> {
let shared = Arc::clone(self.shared.as_ref().expect("one-shot receiver is always initialized"));
loop {
let state = shared.state.load(Ordering::Acquire);
if state & VALUE_READY != 0 {
let value = unsafe { (*shared.value.get()).assume_init_read() };
shared.state.fetch_and(!VALUE_READY, Ordering::Relaxed);
self.shared.take();
return Ok(value);
}
if state & SENDER_CLOSED != 0 {
self.shared.take();
return Err(RecvError);
}
unsafe {
lyquor_api::__wait(shared.state.as_ptr() as GuestUsize, state, -1, 0 as GuestUsize);
}
}
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
if let Some(shared) = self.shared.take() {
shared.state.fetch_or(RECEIVER_CLOSED, Ordering::Release);
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RecvError;
impl fmt::Display for RecvError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("one-shot sender dropped without sending a value")
}
}
impl std::error::Error for RecvError {}
pub(crate) fn channel<T>() -> (Sender<T>, Receiver<T>) {
let shared = Arc::new(Shared::new());
(
Sender {
shared: Some(Arc::clone(&shared)),
},
Receiver { shared: Some(shared) },
)
}
}
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)
}
}