use std::{
arch::wasm32,
sync::{
atomic::{AtomicU32, Ordering},
Mutex,
},
task::{Poll, Waker},
};
use futures::future::poll_fn;
use super::utils::SpinLockMutex;
pub struct Signal {
waiters: Mutex<Vec<Waker>>,
value: AtomicU32,
}
impl Signal {
pub fn new() -> Self {
Self {
waiters: Mutex::new(Default::default()),
value: AtomicU32::new(0),
}
}
pub fn signal(&self) {
self.value.store(1, Ordering::SeqCst);
unsafe {
wasm32::memory_atomic_notify(&self.value as *const AtomicU32 as *mut i32, i32::MAX as u32);
}
for waiter in self.waiters.lock_spin().unwrap().drain(..) {
waiter.wake();
}
}
pub fn wait(&self) {
while self.value.load(Ordering::Relaxed) == 0 {
unsafe {
wasm32::memory_atomic_wait32(&self.value as *const AtomicU32 as *mut i32, 0, -1);
}
}
}
pub async fn wait_async(&self) {
poll_fn(|cx| {
self.waiters.lock_spin().unwrap().push(cx.waker().clone());
if self.value.load(Ordering::Relaxed) == 1 {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await
}
}