use core::{cell::UnsafeCell, time::Duration};
use crate::{
sync::{RawRwLock, RawRwLockTimed},
sys::sync::{Condvar, LwMutex, Mutex, SemaMutex},
};
struct State {
readers: u32,
writer_active: bool,
write_waiters: u32,
}
pub struct RwLock {
lock: Mutex,
cond: Condvar,
state: UnsafeCell<State>,
}
impl RwLock {
#[inline]
pub const fn new() -> Self {
Self {
lock: Mutex::new(),
cond: Condvar::new(),
state: UnsafeCell::new(State {
readers: 0,
writer_active: false,
write_waiters: 0,
}),
}
}
#[inline]
fn read(&self) {
self.lock.lock();
let state = unsafe { self.state() };
loop {
if !state.writer_active && state.write_waiters == 0 {
break;
}
unsafe { self.cond.wait(&self.lock) };
}
state.readers += 1;
unsafe { self.lock.unlock() };
}
#[inline]
fn try_read(&self) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
let ok = !state.writer_active && state.write_waiters == 0;
if ok {
state.readers += 1;
}
unsafe { self.lock.unlock() };
ok
}
#[inline]
fn try_read_for(&self, timeout: Duration) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
loop {
if !state.writer_active && state.write_waiters == 0 {
break;
}
let res = unsafe { self.cond.wait_timeout(&self.lock, timeout) };
if !res {
unsafe { self.lock.unlock() };
return false;
}
}
state.readers += 1;
unsafe { self.lock.unlock() };
true
}
#[inline]
fn write(&self) {
self.lock.lock();
let state = unsafe { self.state() };
state.write_waiters += 1;
loop {
if !state.writer_active && state.readers == 0 {
break;
}
unsafe { self.cond.wait(&self.lock) };
}
state.write_waiters -= 1;
state.writer_active = true;
unsafe { self.lock.unlock() };
}
#[inline]
fn try_write(&self) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
let ok = !state.writer_active && state.readers == 0;
if ok {
state.writer_active = true;
}
unsafe { self.lock.unlock() };
ok
}
#[inline]
fn try_write_for(&self, timeout: Duration) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
state.write_waiters += 1;
loop {
if !state.writer_active && state.readers == 0 {
break;
}
let res = unsafe { self.cond.wait_timeout(&self.lock, timeout) };
if !res {
unsafe { self.lock.unlock() };
return false;
}
}
state.write_waiters -= 1;
state.writer_active = true;
unsafe { self.lock.unlock() };
true
}
#[inline]
#[track_caller]
unsafe fn read_unlock(&self) {
self.lock.lock();
let state = unsafe { self.state() };
debug_assert!(state.readers > 0, "`read_unlock` without reader");
let readers = {
let r = state.readers - 1;
state.readers = r;
r
};
if readers == 0 && state.write_waiters > 0 {
self.cond.notify_one();
}
unsafe { self.lock.unlock() };
}
#[inline]
#[track_caller]
unsafe fn write_unlock(&self) {
self.lock.lock();
let state = unsafe { self.state() };
debug_assert!(state.writer_active, "`write_unlock` without writer");
state.writer_active = false;
if state.write_waiters > 0 {
self.cond.notify_one();
} else {
self.cond.notify_all();
}
unsafe { self.lock.unlock() };
}
#[inline]
#[track_caller]
unsafe fn downgrade(&self) {
self.lock.lock();
let state = unsafe { self.state() };
debug_assert!(state.writer_active, "downgrade without writer");
state.writer_active = false;
state.readers = state.readers.saturating_add(1);
self.cond.notify_all();
unsafe { self.lock.unlock() };
}
}
impl RwLock {
unsafe fn state(&self) -> &mut State {
unsafe { &mut *self.state.get() }
}
}
unsafe impl Sync for RwLock {}
impl crate::private::Sealed for RwLock {}
impl RawRwLock for RwLock {
const NEW: Self = Self::new();
#[inline]
fn read(&self) {
self.read()
}
#[inline]
fn try_read(&self) -> bool {
self.try_read()
}
#[inline]
fn write(&self) {
self.write();
}
#[inline]
fn try_write(&self) -> bool {
self.try_write()
}
#[inline]
unsafe fn read_unlock(&self) {
unsafe { self.read_unlock() };
}
#[inline]
unsafe fn write_unlock(&self) {
unsafe { self.write_unlock() };
}
#[inline]
#[track_caller]
unsafe fn downgrade(&self) {
unsafe { self.downgrade() };
}
}
impl RawRwLockTimed for RwLock {
#[inline]
fn try_read_for(&self, timeout: Duration) -> bool {
self.try_read_for(timeout)
}
#[inline]
fn try_write_for(&self, timeout: Duration) -> bool {
self.try_write_for(timeout)
}
}
pub struct LwRwLock {
lock: LwMutex,
cond: Condvar,
state: UnsafeCell<State>,
}
impl LwRwLock {
#[inline]
pub const fn new() -> Self {
Self {
lock: LwMutex::new(),
cond: Condvar::new(),
state: UnsafeCell::new(State {
readers: 0,
writer_active: false,
write_waiters: 0,
}),
}
}
#[inline]
fn read(&self) {
self.lock.lock();
let state = unsafe { self.state() };
loop {
if !state.writer_active && state.write_waiters == 0 {
break;
}
unsafe { self.cond.wait(&self.lock) };
}
state.readers += 1;
unsafe { self.lock.unlock() };
}
#[inline]
fn try_read(&self) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
let ok = !state.writer_active && state.write_waiters == 0;
if ok {
state.readers += 1;
}
unsafe { self.lock.unlock() };
ok
}
#[inline]
fn try_read_for(&self, timeout: Duration) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
loop {
if !state.writer_active && state.write_waiters == 0 {
break;
}
let res = unsafe { self.cond.wait_timeout(&self.lock, timeout) };
if !res {
unsafe { self.lock.unlock() };
return false;
}
}
state.readers += 1;
unsafe { self.lock.unlock() };
true
}
#[inline]
fn write(&self) {
self.lock.lock();
let state = unsafe { self.state() };
state.write_waiters += 1;
loop {
if !state.writer_active && state.readers == 0 {
break;
}
unsafe { self.cond.wait(&self.lock) };
}
state.write_waiters -= 1;
state.writer_active = true;
unsafe { self.lock.unlock() };
}
#[inline]
fn try_write(&self) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
let ok = !state.writer_active && state.readers == 0;
if ok {
state.writer_active = true;
}
unsafe { self.lock.unlock() };
ok
}
#[inline]
fn try_write_for(&self, timeout: Duration) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
state.write_waiters += 1;
loop {
if !state.writer_active && state.readers == 0 {
break;
}
let res = unsafe { self.cond.wait_timeout(&self.lock, timeout) };
if !res {
unsafe { self.lock.unlock() };
return false;
}
}
state.write_waiters -= 1;
state.writer_active = true;
unsafe { self.lock.unlock() };
true
}
#[inline]
#[track_caller]
unsafe fn read_unlock(&self) {
self.lock.lock();
let state = unsafe { self.state() };
debug_assert!(state.readers > 0, "`read_unlock` without reader");
let readers = {
let r = state.readers - 1;
state.readers = r;
r
};
if readers == 0 && state.write_waiters > 0 {
self.cond.notify_one();
}
unsafe { self.lock.unlock() };
}
#[inline]
#[track_caller]
unsafe fn write_unlock(&self) {
self.lock.lock();
let state = unsafe { self.state() };
debug_assert!(state.writer_active, "`write_unlock` without writer");
state.writer_active = false;
if state.write_waiters > 0 {
self.cond.notify_one();
} else {
self.cond.notify_all();
}
unsafe { self.lock.unlock() };
}
#[inline]
#[track_caller]
unsafe fn downgrade(&self) {
self.lock.lock();
let state = unsafe { self.state() };
debug_assert!(state.writer_active, "downgrade without writer");
state.writer_active = false;
state.readers = state.readers.saturating_add(1);
self.cond.notify_all();
unsafe { self.lock.unlock() };
}
}
impl LwRwLock {
unsafe fn state(&self) -> &mut State {
unsafe { &mut *self.state.get() }
}
}
unsafe impl Sync for LwRwLock {}
impl crate::private::Sealed for LwRwLock {}
impl RawRwLock for LwRwLock {
const NEW: Self = Self::new();
#[inline]
fn read(&self) {
self.read()
}
#[inline]
fn try_read(&self) -> bool {
self.try_read()
}
#[inline]
fn write(&self) {
self.write();
}
#[inline]
fn try_write(&self) -> bool {
self.try_write()
}
#[inline]
unsafe fn read_unlock(&self) {
unsafe { self.read_unlock() };
}
#[inline]
unsafe fn write_unlock(&self) {
unsafe { self.write_unlock() };
}
#[inline]
#[track_caller]
unsafe fn downgrade(&self) {
unsafe { self.downgrade() };
}
}
impl RawRwLockTimed for LwRwLock {
#[inline]
fn try_read_for(&self, timeout: Duration) -> bool {
self.try_read_for(timeout)
}
#[inline]
fn try_write_for(&self, timeout: Duration) -> bool {
self.try_write_for(timeout)
}
}
pub struct SemaRwLock {
lock: SemaMutex,
cond: Condvar,
state: UnsafeCell<State>,
}
impl SemaRwLock {
#[inline]
pub const fn new() -> Self {
Self {
lock: SemaMutex::new(),
cond: Condvar::new(),
state: UnsafeCell::new(State {
readers: 0,
writer_active: false,
write_waiters: 0,
}),
}
}
#[inline]
fn read(&self) {
self.lock.lock();
let state = unsafe { self.state() };
loop {
if !state.writer_active && state.write_waiters == 0 {
break;
}
unsafe { self.cond.wait(&self.lock) };
}
state.readers += 1;
unsafe { self.lock.unlock() };
}
#[inline]
fn try_read(&self) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
let ok = !state.writer_active && state.write_waiters == 0;
if ok {
state.readers += 1;
}
unsafe { self.lock.unlock() };
ok
}
#[inline]
fn try_read_for(&self, timeout: Duration) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
loop {
if !state.writer_active && state.write_waiters == 0 {
break;
}
let res = unsafe { self.cond.wait_timeout(&self.lock, timeout) };
if !res {
unsafe { self.lock.unlock() };
return false;
}
}
state.readers += 1;
unsafe { self.lock.unlock() };
true
}
#[inline]
fn write(&self) {
self.lock.lock();
let state = unsafe { self.state() };
state.write_waiters += 1;
loop {
if !state.writer_active && state.readers == 0 {
break;
}
unsafe { self.cond.wait(&self.lock) };
}
state.write_waiters -= 1;
state.writer_active = true;
unsafe { self.lock.unlock() };
}
#[inline]
fn try_write(&self) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
let ok = !state.writer_active && state.readers == 0;
if ok {
state.writer_active = true;
}
unsafe { self.lock.unlock() };
ok
}
#[inline]
fn try_write_for(&self, timeout: Duration) -> bool {
self.lock.lock();
let state = unsafe { self.state() };
state.write_waiters += 1;
loop {
if !state.writer_active && state.readers == 0 {
break;
}
let res = unsafe { self.cond.wait_timeout(&self.lock, timeout) };
if !res {
unsafe { self.lock.unlock() };
return false;
}
}
state.write_waiters -= 1;
state.writer_active = true;
unsafe { self.lock.unlock() };
true
}
#[inline]
#[track_caller]
unsafe fn read_unlock(&self) {
self.lock.lock();
let state = unsafe { self.state() };
debug_assert!(state.readers > 0, "`read_unlock` without reader");
let readers = {
let r = state.readers - 1;
state.readers = r;
r
};
if readers == 0 && state.write_waiters > 0 {
self.cond.notify_one();
}
unsafe { self.lock.unlock() };
}
#[inline]
#[track_caller]
unsafe fn write_unlock(&self) {
self.lock.lock();
let state = unsafe { self.state() };
debug_assert!(state.writer_active, "`write_unlock` without writer");
state.writer_active = false;
if state.write_waiters > 0 {
self.cond.notify_one();
} else {
self.cond.notify_all();
}
unsafe { self.lock.unlock() };
}
#[inline]
#[track_caller]
unsafe fn downgrade(&self) {
self.lock.lock();
let state = unsafe { self.state() };
debug_assert!(state.writer_active, "downgrade without writer");
state.writer_active = false;
state.readers = state.readers.saturating_add(1);
self.cond.notify_all();
unsafe { self.lock.unlock() };
}
}
impl SemaRwLock {
unsafe fn state(&self) -> &mut State {
unsafe { &mut *self.state.get() }
}
}
unsafe impl Sync for SemaRwLock {}
impl crate::private::Sealed for SemaRwLock {}
impl RawRwLock for SemaRwLock {
const NEW: Self = Self::new();
#[inline]
fn read(&self) {
self.read()
}
#[inline]
fn try_read(&self) -> bool {
self.try_read()
}
#[inline]
fn write(&self) {
self.write();
}
#[inline]
fn try_write(&self) -> bool {
self.try_write()
}
#[inline]
unsafe fn read_unlock(&self) {
unsafe { self.read_unlock() };
}
#[inline]
unsafe fn write_unlock(&self) {
unsafe { self.write_unlock() };
}
#[inline]
#[track_caller]
unsafe fn downgrade(&self) {
unsafe { self.downgrade() };
}
}
impl RawRwLockTimed for SemaRwLock {
#[inline]
fn try_read_for(&self, timeout: Duration) -> bool {
self.try_read_for(timeout)
}
#[inline]
fn try_write_for(&self, timeout: Duration) -> bool {
self.try_write_for(timeout)
}
}