|
1 | 1 | //! This module is full of hackery and dark magic.
|
2 | 2 | //! Either spend a day fixing it and quietly submit a PR or don't mention it to anybody.
|
3 | 3 | use core::{mem, ptr};
|
| 4 | +use std::{marker::PhantomData, mem::ManuallyDrop}; |
| 5 | + |
| 6 | +use lock_api::{RawRwLock, RawRwLockDowngrade, RwLockReadGuard, RwLockWriteGuard}; |
4 | 7 |
|
5 | 8 | pub const fn ptr_size_bits() -> usize {
|
6 | 9 | mem::size_of::<usize>() * 8
|
@@ -30,3 +33,92 @@ impl Drop for AbortOnPanic {
|
30 | 33 | }
|
31 | 34 | }
|
32 | 35 | }
|
| 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