rt/rust/src/sync/rwlock.rs

157 lines
3.8 KiB
Rust

use core::{
cell::UnsafeCell,
marker::{PhantomData, PhantomPinned},
ops::{Deref, DerefMut},
panic::{RefUnwindSafe, UnwindSafe},
};
use crate::{
bindings::{
rt_cond, rt_mutex, rt_rwlock, rt_rwlock_rdlock, rt_rwlock_unlock, rt_rwlock_wrlock,
},
list::list_init,
sync::semaphore::c_sem_init,
};
pub struct RwLock<T: ?Sized> {
l: UnsafeCell<rt_rwlock>,
_pin_marker: PhantomPinned,
data: UnsafeCell<T>,
}
unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
impl<T: ?Sized> UnwindSafe for RwLock<T> {}
impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}
impl<T> RwLock<T> {
pub const fn init(lock: &'static RwLock<T>, t: T) -> RwLock<T> {
let l = unsafe { &*(lock.l.get() as *const rt_rwlock) };
RwLock {
l: UnsafeCell::new(rt_rwlock {
m: rt_mutex {
holder: 0,
wait_list: list_init(&l.m.wait_list),
list: list_init(&l.m.list),
},
rcond: rt_cond {
sem: c_sem_init(&l.rcond.sem, 0, 0),
},
wcond: rt_cond {
sem: c_sem_init(&l.wcond.sem, 0, 0),
},
num_readers: 0,
num_writers: 0,
}),
_pin_marker: PhantomPinned,
data: UnsafeCell::new(t),
}
}
}
impl<T: ?Sized> RwLock<T> {
pub fn read(&self) -> RwLockReadGuard<'_, T> {
unsafe {
rt_rwlock_rdlock(self.l.get());
}
RwLockReadGuard::new(self)
}
pub fn write(&self) -> RwLockWriteGuard<'_, T> {
unsafe {
rt_rwlock_wrlock(self.l.get());
}
RwLockWriteGuard::new(self)
}
// Probably not useful because this RwLock must be static.
pub fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
}
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
lock: &'a RwLock<T>,
_unsend_marker: PhantomData<*const ()>,
}
impl<T: ?Sized> RwLockReadGuard<'_, T> {
fn new(lock: &RwLock<T>) -> RwLockReadGuard<T> {
RwLockReadGuard {
lock,
_unsend_marker: PhantomData,
}
}
}
unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, 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> {
#[inline]
fn drop(&mut self) {
unsafe { rt_rwlock_unlock(self.lock.l.get()) }
}
}
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
lock: &'a RwLock<T>,
_unsend_marker: PhantomData<*const ()>,
}
impl<T: ?Sized> RwLockWriteGuard<'_, T> {
fn new(lock: &RwLock<T>) -> RwLockWriteGuard<T> {
RwLockWriteGuard {
lock,
_unsend_marker: PhantomData,
}
}
}
unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, 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> {
#[inline]
fn drop(&mut self) {
unsafe { rt_rwlock_unlock(self.lock.l.get()) }
}
}
#[macro_export]
macro_rules! rwlock {
($name: ident, $type: ty, $data: expr) => {
static $name: $crate::sync::RwLock<$type> = $crate::sync::RwLock::init(&$name, $data);
};
}
#[cfg(test)]
mod tests {
#[test]
fn fast_path() {
rwlock!(LOCK, i32, 0);
*LOCK.write() += 1;
assert!(*LOCK.read() == 1);
}
}