1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
use crate::rt;
use std::ops;
use std::sync::{LockResult, TryLockError, TryLockResult};
/// Mock implementation of `std::sync::RwLock`
#[derive(Debug)]
pub struct RwLock<T> {
object: rt::RwLock,
data: std::sync::RwLock<T>,
}
/// Mock implementation of `std::sync::RwLockReadGuard`
#[derive(Debug)]
pub struct RwLockReadGuard<'a, T> {
lock: &'a RwLock<T>,
data: Option<std::sync::RwLockReadGuard<'a, T>>,
}
/// Mock implementation of `std::sync::rwLockWriteGuard`
#[derive(Debug)]
pub struct RwLockWriteGuard<'a, T> {
lock: &'a RwLock<T>,
/// `data` is an Option so that the Drop impl can drop the std guard and release the std lock
/// before releasing the loom mock lock, as that might cause another thread to acquire the lock
data: Option<std::sync::RwLockWriteGuard<'a, T>>,
}
impl<T> RwLock<T> {
/// Creates a new rwlock in an unlocked state ready for use.
pub fn new(data: T) -> RwLock<T> {
RwLock {
data: std::sync::RwLock::new(data),
object: rt::RwLock::new(),
}
}
/// Locks this rwlock with shared read access, blocking the current
/// thread until it can be acquired.
///
/// The calling thread will be blocked until there are no more writers
/// which hold the lock. There may be other readers currently inside the
/// lock when this method returns. This method does not provide any
/// guarantees with respect to the ordering of whether contentious readers
/// or writers will acquire the lock first.
#[track_caller]
pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
self.object.acquire_read_lock(location!());
Ok(RwLockReadGuard {
lock: self,
data: Some(self.data.try_read().expect("loom::RwLock state corrupt")),
})
}
/// Attempts to acquire this rwlock with shared read access.
///
/// If the access could not be granted at this time, then Err is returned.
/// Otherwise, an RAII guard is returned which will release the shared
/// access when it is dropped.
///
/// This function does not block.
#[track_caller]
pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> {
if self.object.try_acquire_read_lock(location!()) {
Ok(RwLockReadGuard {
lock: self,
data: Some(self.data.try_read().expect("loom::RwLock state corrupt")),
})
} else {
Err(TryLockError::WouldBlock)
}
}
/// Locks this rwlock with exclusive write access, blocking the current
/// thread until it can be acquired.
///
/// This function will not return while other writers or other readers
/// currently have access to the lock.
#[track_caller]
pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
self.object.acquire_write_lock(location!());
Ok(RwLockWriteGuard {
lock: self,
data: Some(self.data.try_write().expect("loom::RwLock state corrupt")),
})
}
/// Attempts to lock this rwlock with exclusive write access.
///
/// If the lock could not be acquired at this time, then Err is returned.
/// Otherwise, an RAII guard is returned which will release the lock when
/// it is dropped.
///
/// This function does not block.
#[track_caller]
pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> {
if self.object.try_acquire_write_lock(location!()) {
Ok(RwLockWriteGuard {
lock: self,
data: Some(self.data.try_write().expect("loom::RwLock state corrupt")),
})
} else {
Err(TryLockError::WouldBlock)
}
}
/// Returns a mutable reference to the underlying data.
pub fn get_mut(&mut self) -> LockResult<&mut T> {
Ok(self.data.get_mut().expect("loom::RwLock state corrupt"))
}
/// Consumes this `RwLock`, returning the underlying data.
pub fn into_inner(self) -> LockResult<T> {
Ok(self.data.into_inner().expect("loom::RwLock state corrupt"))
}
}
impl<T: Default> Default for RwLock<T> {
/// Creates a `RwLock<T>`, with the `Default` value for T.
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T> From<T> for RwLock<T> {
/// Creates a new rwlock in an unlocked state ready for use.
/// This is equivalent to [`RwLock::new`].
fn from(t: T) -> Self {
Self::new(t)
}
}
impl<'a, T> ops::Deref for RwLockReadGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
self.data.as_ref().unwrap().deref()
}
}
impl<'a, T: 'a> Drop for RwLockReadGuard<'a, T> {
fn drop(&mut self) {
self.data = None;
self.lock.object.release_read_lock()
}
}
impl<'a, T> ops::Deref for RwLockWriteGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
self.data.as_ref().unwrap().deref()
}
}
impl<'a, T> ops::DerefMut for RwLockWriteGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
self.data.as_mut().unwrap().deref_mut()
}
}
impl<'a, T: 'a> Drop for RwLockWriteGuard<'a, T> {
fn drop(&mut self) {
self.data = None;
self.lock.object.release_write_lock()
}
}