use std::sync::atomic::Ordering;
const STATE_UNLOCKED: usize = 0;
const STATE_LOCKED_W: usize = std::usize::MAX;
pub(crate) struct ReadIOLock<'a> {
iostate: &'a mut IOLock,
}
impl<'a> Drop for ReadIOLock<'a> {
fn drop(&mut self) {
self.iostate.state.fetch_sub(1, Ordering::SeqCst);
}
}
pub(crate) struct WriteIOLock<'a> {
iostate: &'a mut IOLock,
}
impl<'a> Drop for WriteIOLock<'a> {
fn drop(&mut self) {
self.iostate.state.store(STATE_UNLOCKED, Ordering::SeqCst);
}
}
#[repr(C)]
pub(crate) struct IOLock {
state: std::sync::atomic::AtomicUsize,
}
impl IOLock {
pub const fn new() -> IOLock {
IOLock {
state: std::sync::atomic::AtomicUsize::new(0),
}
}
pub fn lock_read<'a>(&'a mut self) -> () {
loop {
let value = self.state.load(Ordering::SeqCst);
if value == STATE_LOCKED_W { continue }
if self.state.compare_and_swap(value, value + 1, Ordering::SeqCst) == value {
break;
}
}
}
pub fn lock_write<'a>(&'a mut self) -> () {
loop {
let value = self.state.load(Ordering::SeqCst);
if value != STATE_UNLOCKED { continue }
if self.state
.compare_and_swap(value, STATE_LOCKED_W, Ordering::SeqCst) == value
{
break;
}
}
}
}