use alloc::collections::VecDeque;
use alloc::sync::Arc;
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::sync::atomic::{AtomicU32, Ordering};
#[cfg(windows)]
mod os {
use core::sync::atomic::AtomicU32;
#[link(name = "api-ms-win-core-synch-l1-2-0", kind = "raw-dylib")]
unsafe extern "system" {
fn WaitOnAddress(addr: *const u32, cmp: *const u32, size: usize, ms: u32) -> i32;
fn WakeByAddressSingle(addr: *const u32);
fn WakeByAddressAll(addr: *const u32);
}
pub fn wait(a: &AtomicU32, expected: u32, ms: Option<u32>) -> bool {
let t = ms.map_or(u32::MAX, |m| m.min(u32::MAX - 1));
unsafe { WaitOnAddress(a.as_ptr(), &expected, 4, t) != 0 }
}
pub fn wake_one(a: &AtomicU32) {
unsafe { WakeByAddressSingle(a.as_ptr()) }
}
pub fn wake_all(a: &AtomicU32) {
unsafe { WakeByAddressAll(a.as_ptr()) }
}
}
#[cfg(target_os = "linux")]
mod os {
use core::sync::atomic::AtomicU32;
use rt::os::{syscall6, SYS_FUTEX};
const FUTEX_WAIT_PRIVATE: usize = 128;
const FUTEX_WAKE_PRIVATE: usize = 129;
const ETIMEDOUT: isize = 110;
pub fn wait(a: &AtomicU32, expected: u32, ms: Option<u32>) -> bool {
let ts = ms.map(|m| [(m / 1000) as i64, (m % 1000) as i64 * 1_000_000]);
let tp = ts.as_ref().map_or(0, |t| t.as_ptr() as usize);
let r = unsafe { syscall6(SYS_FUTEX, a.as_ptr() as usize, FUTEX_WAIT_PRIVATE, expected as usize, tp, 0, 0) };
r != -ETIMEDOUT
}
pub fn wake_one(a: &AtomicU32) {
unsafe { syscall6(SYS_FUTEX, a.as_ptr() as usize, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0) };
}
pub fn wake_all(a: &AtomicU32) {
unsafe { syscall6(SYS_FUTEX, a.as_ptr() as usize, FUTEX_WAKE_PRIVATE, i32::MAX as usize, 0, 0, 0) };
}
}
pub(crate) use os::{wait, wake_all, wake_one};
pub struct Mutex<T: ?Sized> {
state: AtomicU32,
data: UnsafeCell<T>,
}
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
impl<T> Mutex<T> {
pub const fn new(v: T) -> Mutex<T> {
Mutex { state: AtomicU32::new(0), data: UnsafeCell::new(v) }
}
pub fn into_inner(self) -> T {
self.data.into_inner()
}
}
impl<T: Default> Default for Mutex<T> {
fn default() -> Self {
Mutex::new(T::default())
}
}
impl<T: ?Sized> Mutex<T> {
pub fn lock(&self) -> MutexGuard<'_, T> {
if self.state.compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed).is_err() {
self.lock_contended();
}
MutexGuard { m: self }
}
pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
self.state.compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed).ok().map(|_| MutexGuard { m: self })
}
pub fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
fn spin(&self) -> u32 {
let mut n = 100;
loop {
let s = self.state.load(Ordering::Relaxed);
if s != 1 || n == 0 {
return s;
}
n -= 1;
core::hint::spin_loop();
}
}
fn lock_contended(&self) {
let mut s = self.spin();
if s == 0 {
match self.state.compare_exchange(0, 1, Ordering::Acquire, Ordering::Relaxed) {
Ok(_) => return,
Err(e) => s = e,
}
}
loop {
if s != 2 && self.state.swap(2, Ordering::Acquire) == 0 {
return;
}
wait(&self.state, 2, None);
s = self.spin();
}
}
fn unlock(&self) {
if self.state.swap(0, Ordering::Release) == 2 {
wake_one(&self.state);
}
}
}
pub struct MutexGuard<'a, T: ?Sized> {
m: &'a Mutex<T>,
}
impl<T: ?Sized> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.m.data.get() }
}
}
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.m.data.get() }
}
}
impl<T: ?Sized> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
self.m.unlock();
}
}
#[derive(Default)]
pub struct Condvar {
seq: AtomicU32,
}
impl Condvar {
pub const fn new() -> Condvar {
Condvar { seq: AtomicU32::new(0) }
}
pub fn wait<'a, T: ?Sized>(&self, g: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
self.wait_timeout(g, None).0
}
pub fn wait_timeout<'a, T: ?Sized>(&self, g: MutexGuard<'a, T>, ms: Option<u32>) -> (MutexGuard<'a, T>, bool) {
let m = g.m;
let s = self.seq.load(Ordering::Relaxed);
drop(g);
let woken = wait(&self.seq, s, ms);
(m.lock(), !woken)
}
pub fn wait_while<'a, T: ?Sized>(&self, mut g: MutexGuard<'a, T>, mut cond: impl FnMut(&mut T) -> bool) -> MutexGuard<'a, T> {
while cond(&mut g) {
g = self.wait(g);
}
g
}
pub fn notify_one(&self) {
self.seq.fetch_add(1, Ordering::Relaxed);
wake_one(&self.seq);
}
pub fn notify_all(&self) {
self.seq.fetch_add(1, Ordering::Relaxed);
wake_all(&self.seq);
}
}
#[derive(Default)]
struct RwState {
readers: u32,
writer: bool,
writers_waiting: u32,
}
pub struct RwLock<T: ?Sized> {
st: Mutex<RwState>,
cv: Condvar,
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> {
pub const fn new(v: T) -> RwLock<T> {
RwLock { st: Mutex::new(RwState { readers: 0, writer: false, writers_waiting: 0 }), cv: Condvar::new(), data: UnsafeCell::new(v) }
}
}
impl<T: ?Sized> RwLock<T> {
pub fn read(&self) -> RwReadGuard<'_, T> {
let mut s = self.cv.wait_while(self.st.lock(), |s| s.writer || s.writers_waiting > 0);
s.readers += 1;
RwReadGuard { l: self }
}
pub fn write(&self) -> RwWriteGuard<'_, T> {
let mut s = self.st.lock();
s.writers_waiting += 1;
let mut s = self.cv.wait_while(s, |s| s.writer || s.readers > 0);
s.writers_waiting -= 1;
s.writer = true;
RwWriteGuard { l: self }
}
}
pub struct RwReadGuard<'a, T: ?Sized> {
l: &'a RwLock<T>,
}
impl<T: ?Sized> Deref for RwReadGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.l.data.get() }
}
}
impl<T: ?Sized> Drop for RwReadGuard<'_, T> {
fn drop(&mut self) {
let mut s = self.l.st.lock();
s.readers -= 1;
if s.readers == 0 {
self.l.cv.notify_all();
}
}
}
pub struct RwWriteGuard<'a, T: ?Sized> {
l: &'a RwLock<T>,
}
impl<T: ?Sized> Deref for RwWriteGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.l.data.get() }
}
}
impl<T: ?Sized> DerefMut for RwWriteGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.l.data.get() }
}
}
impl<T: ?Sized> Drop for RwWriteGuard<'_, T> {
fn drop(&mut self) {
self.l.st.lock().writer = false;
self.l.cv.notify_all();
}
}
struct ChanState<T> {
items: VecDeque<T>,
cap: usize,
senders: usize,
receiver: bool,
}
struct Chan<T> {
st: Mutex<ChanState<T>>,
not_empty: Condvar,
not_full: Condvar,
}
pub fn channel<T>(cap: usize) -> (Sender<T>, Receiver<T>) {
let c = Arc::new(Chan {
st: Mutex::new(ChanState { items: VecDeque::new(), cap: cap.max(1), senders: 1, receiver: true }),
not_empty: Condvar::new(),
not_full: Condvar::new(),
});
(Sender { c: c.clone() }, Receiver { c })
}
pub struct Sender<T> {
c: Arc<Chan<T>>,
}
pub struct Receiver<T> {
c: Arc<Chan<T>>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RecvError {
Timeout,
Disconnected,
}
impl<T> Sender<T> {
pub fn send(&self, v: T) -> Result<(), T> {
let mut s = self.c.not_full.wait_while(self.c.st.lock(), |s| s.receiver && s.items.len() >= s.cap);
if !s.receiver {
return Err(v);
}
s.items.push_back(v);
drop(s);
self.c.not_empty.notify_one();
Ok(())
}
pub fn try_send(&self, v: T) -> Result<(), T> {
let mut s = self.c.st.lock();
if !s.receiver || s.items.len() >= s.cap {
return Err(v);
}
s.items.push_back(v);
drop(s);
self.c.not_empty.notify_one();
Ok(())
}
}
impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
self.c.st.lock().senders += 1;
Sender { c: self.c.clone() }
}
}
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
let mut s = self.c.st.lock();
s.senders -= 1;
if s.senders == 0 {
drop(s);
self.c.not_empty.notify_all();
}
}
}
impl<T> Receiver<T> {
pub fn recv(&self) -> Option<T> {
let mut s = self.c.not_empty.wait_while(self.c.st.lock(), |s| s.items.is_empty() && s.senders > 0);
let v = s.items.pop_front();
drop(s);
if v.is_some() {
self.c.not_full.notify_one();
}
v
}
pub fn recv_timeout(&self, ms: u32) -> Result<T, RecvError> {
let deadline = crate::time_us().saturating_add(ms as u64 * 1000);
let mut s = self.c.st.lock();
loop {
if let Some(v) = s.items.pop_front() {
drop(s);
self.c.not_full.notify_one();
return Ok(v);
}
if s.senders == 0 {
return Err(RecvError::Disconnected);
}
let now = crate::time_us();
if now >= deadline {
return Err(RecvError::Timeout);
}
let left = ((deadline - now).div_ceil(1000)).min(u32::MAX as u64) as u32;
s = self.c.not_empty.wait_timeout(s, Some(left)).0;
}
}
pub fn try_recv(&self) -> Option<T> {
let v = self.c.st.lock().items.pop_front();
if v.is_some() {
self.c.not_full.notify_one();
}
v
}
pub fn len(&self) -> usize {
self.c.st.lock().items.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
let mut s = self.c.st.lock();
s.receiver = false;
s.items.clear();
drop(s);
self.c.not_full.notify_all();
}
}