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
use std::{
cell::UnsafeCell,
ops::{Deref, DerefMut},
sync::atomic::{AtomicBool, Ordering},
};
///
/// A special RwLock which can be locked exclusively any number of consecutive times,
/// but once initially locked shared, can never be unlocked.
/// This allows unguarded reads to occur
pub struct FusedRwLock<T: ?Sized> {
inner: parking_lot::RwLock<()>,
locked: AtomicBool,
object: UnsafeCell<T>,
}
unsafe impl<T: ?Sized + Send> Send for FusedRwLock<T> {}
unsafe impl<T: ?Sized + Send + Sync> Sync for FusedRwLock<T> {}
impl<T: Default> Default for FusedRwLock<T> {
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T> FusedRwLock<T> {
///
/// Constructs a new, initially unlocked, RwLock
pub const fn new(x: T) -> Self {
Self {
inner: parking_lot::const_rwlock(()),
locked: AtomicBool::new(false),
object: UnsafeCell::new(x),
}
}
///
/// Moves the inner value out of the FusedRwLock.
/// This is sound because self is moved into the function, and thus no other accesses exist
pub fn into_inner(self) -> T {
self.object.into_inner()
}
}
impl<T: ?Sized> FusedRwLock<T> {
///
/// Mutably borrows the interior of the lock, if it has not been locked for reading access
/// This is sound because taking self by &mut statically guarantees no other accesses exist.
/// Returns None if the lock has been locked for reading
pub fn try_get_mut(&mut self) -> Option<&mut T> {
if *self.locked.get_mut() {
Some(self.object.get_mut())
} else {
None
}
}
///
/// Mutably borrows the interior of the lock, even if it has been locked for reading.
/// This function is unsafe because, while not necessarily undefined behaviour, calling this function
/// after it was locked for reading can be used to violate the logical invariant of FusedRwLock.
pub unsafe fn get_mut_unlocked(&mut self) -> &mut T {
self.object.get_mut()
}
///
/// Check if the FusedRwLock has been locked for reading.
/// This does not guarantee any synchronization, even if it returns true. Except where self is reborrowed from &mut,
/// it should only be used as a hint to avoid needless calls to self.try_read
/// A return of true is guaranteed to remain true for the lifetime of the lock.
/// A return of false may be invalidated at any time.
pub fn is_locked(&self) -> bool {
self.locked.load(Ordering::Relaxed)
}
///
/// Locks this FusedRwLock for reading.
/// After this call, it becomes impossible to acquire the lock for writing,
/// and safe code cannot be used to modify the inner value (except inside an UnsafeCell)
pub fn lock(&self) {
let _guard = self.inner.read();
self.locked
.store(true, std::sync::atomic::Ordering::Release)
}
///
/// Returns a shared reference to the interior of the lock, if it has been locked for reading.
pub fn try_read(&self) -> Option<&T> {
if self.locked.load(Ordering::Acquire) {
// Safety:
// Because self.locked is set, the lock can never be borrowed exclusively again
Some(unsafe { &*self.object.get() })
} else {
None
}
}
///
/// Locks the RwLock for reading, and returns a shared reference to the interior of the lock
pub fn read(&self) -> &T {
if !self.is_locked() {
self.lock();
}
self.try_read().unwrap()
}
///
/// Acquires an exclusive lock to the interior of the lock, if this lock has not already been locked for reading.
/// Otherwise, returns None
pub fn try_write(&self) -> Option<FusedRwLockGuard<T>> {
// Optimization, since a true return from self.is_locked is guaranteed to continue forever
if !self.is_locked() {
let guard = self.inner.write();
if !self.is_locked() {
Some(FusedRwLockGuard {
_guard: guard,
// Safety:
// Because self.locked is not set, there are no readers. Other writers are excluded by the fact that the WriteGuard is held.
inner: unsafe { &mut *self.object.get() },
})
} else {
None
}
} else {
None
}
}
}
///
/// An RAII guard that holds exclusive mutable access to the inner object.
pub struct FusedRwLockGuard<'a, T: ?Sized> {
inner: &'a mut T,
_guard: parking_lot::RwLockWriteGuard<'a, ()>,
}
impl<'a, T: ?Sized> Deref for FusedRwLockGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
// SAFETY:
// self.guard ensures that self.cell can be borrowed
self.inner
}
}
impl<'a, T: ?Sized> DerefMut for FusedRwLockGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
// SAFETY:
// self.guard ensures that self.cell can be borrowed
self.inner
}
}