Skip to content

Commit 9535936

Browse files
committed
introduce detached guard abstraction
1 parent 387a8b7 commit 9535936

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

src/lock.rs

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use parking_lot_core::{ParkToken, SpinWait, UnparkToken};
44
pub type RwLock<T> = lock_api::RwLock<RawRwLock, T>;
55
pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>;
66
pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>;
7+
pub type RwLockReadGuardDetached<'a> = crate::util::RwLockReadGuardDetached<'a, RawRwLock>;
8+
pub type RwLockWriteGuardDetached<'a> = crate::util::RwLockWriteGuardDetached<'a, RawRwLock>;
79

810
const READERS_PARKED: usize = 0b0001;
911
const WRITERS_PARKED: usize = 0b0010;

src/util.rs

+92
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! This module is full of hackery and dark magic.
22
//! Either spend a day fixing it and quietly submit a PR or don't mention it to anybody.
33
use core::{mem, ptr};
4+
use std::{marker::PhantomData, mem::ManuallyDrop};
5+
6+
use lock_api::{RawRwLock, RawRwLockDowngrade, RwLockReadGuard, RwLockWriteGuard};
47

58
pub const fn ptr_size_bits() -> usize {
69
mem::size_of::<usize>() * 8
@@ -30,3 +33,92 @@ impl Drop for AbortOnPanic {
3033
}
3134
}
3235
}
36+
37+
38+
/// A [`RwLockReadGuard`], without the data
39+
pub(crate) struct RwLockReadGuardDetached<'a, R: RawRwLock> {
40+
lock: &'a R,
41+
_marker: PhantomData<R::GuardMarker>,
42+
}
43+
44+
impl<R: RawRwLock> Drop for RwLockReadGuardDetached<'_, R> {
45+
fn drop(&mut self) {
46+
// Safety: An RwLockReadGuardDetached always holds a shared lock.
47+
unsafe {
48+
self.lock.unlock_shared();
49+
}
50+
}
51+
}
52+
53+
/// A [`RwLockWriteGuard`], without the data
54+
pub(crate) struct RwLockWriteGuardDetached<'a, R: RawRwLock> {
55+
lock: &'a R,
56+
_marker: PhantomData<R::GuardMarker>,
57+
}
58+
59+
impl<R: RawRwLock> Drop for RwLockWriteGuardDetached<'_, R> {
60+
fn drop(&mut self) {
61+
// Safety: An RwLockWriteGuardDetached always holds an exclusive lock.
62+
unsafe {
63+
self.lock.unlock_exclusive();
64+
}
65+
}
66+
}
67+
68+
impl<'a, R: RawRwLock> RwLockReadGuardDetached<'a, R> {
69+
/// Separates the data from the [`RwLockReadGuard`]
70+
///
71+
/// # Safety
72+
///
73+
/// The data must not outlive the detached guard
74+
pub(crate) unsafe fn detach_from<T>(guard: RwLockReadGuard<'a, R, T>) -> (Self, &'a T) {
75+
let rwlock = RwLockReadGuard::rwlock(&ManuallyDrop::new(guard));
76+
77+
// Safety: There will be no concurrent writes as we are "forgetting" the existing guard,
78+
// with the safety assumption that the caller will not drop the new detached guard early.
79+
let data = unsafe { &*rwlock.data_ptr() };
80+
let guard = RwLockReadGuardDetached {
81+
// Safety: We are imitating the original RwLockReadGuard. It's the callers
82+
// responsibility to not drop the guard early.
83+
lock: unsafe { rwlock.raw() },
84+
_marker: PhantomData,
85+
};
86+
(guard, data)
87+
}
88+
}
89+
90+
impl<'a, R: RawRwLock> RwLockWriteGuardDetached<'a, R> {
91+
/// Separates the data from the [`RwLockWriteGuard`]
92+
///
93+
/// # Safety
94+
///
95+
/// The data must not outlive the detached guard
96+
pub(crate) unsafe fn detach_from<T>(guard: RwLockWriteGuard<'a, R, T>) -> (Self, &'a mut T) {
97+
let rwlock = RwLockWriteGuard::rwlock(&ManuallyDrop::new(guard));
98+
99+
// Safety: There will be no concurrent reads/writes as we are "forgetting" the existing guard,
100+
// with the safety assumption that the caller will not drop the new detached guard early.
101+
let data = unsafe { &mut *rwlock.data_ptr() };
102+
let guard = RwLockWriteGuardDetached {
103+
// Safety: We are imitating the original RwLockWriteGuard. It's the callers
104+
// responsibility to not drop the guard early.
105+
lock: unsafe { rwlock.raw() },
106+
_marker: PhantomData,
107+
};
108+
(guard, data)
109+
}
110+
}
111+
112+
impl<'a, R: RawRwLockDowngrade> RwLockWriteGuardDetached<'a, R> {
113+
/// # Safety
114+
///
115+
/// The associated data must not mut mutated after downgrading
116+
pub(crate) unsafe fn downgrade(self) -> RwLockReadGuardDetached<'a, R> {
117+
// Safety: An RwLockWriteGuardDetached always holds an exclusive lock.
118+
unsafe { self.lock.downgrade() }
119+
RwLockReadGuardDetached {
120+
lock: self.lock,
121+
_marker: self._marker,
122+
}
123+
}
124+
}

0 commit comments

Comments
 (0)