Skip to content

Commit 7bf6f3c

Browse files
committed
Implement lockorder checking on RwLocks in debug_sync
1 parent 82bbb80 commit 7bf6f3c

File tree

1 file changed

+77
-13
lines changed

1 file changed

+77
-13
lines changed

lightning/src/debug_sync.rs

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,21 @@ impl MutexMetadata {
7474
}
7575
}
7676

77-
fn pre_lock(this: &Arc<MutexMetadata>) {
77+
fn pre_lock(this: &Arc<MutexMetadata>, read: bool) {
7878
MUTEXES_HELD.with(|held| {
7979
// For each mutex which is currently locked, check that no mutex's locked-before
8080
// set includes the mutex we're about to lock, which would imply a lockorder
8181
// inversion.
8282
for locked in held.borrow().iter() {
83+
if read && *locked == *this {
84+
// Recursive read locks are explicitly allowed
85+
return;
86+
}
87+
}
88+
for locked in held.borrow().iter() {
89+
if !read && *locked == *this {
90+
panic!("Tried to lock a mutex while it was held!");
91+
}
8392
for locked_dep in locked.locked_before.lock().unwrap().iter() {
8493
if *locked_dep == *this {
8594
#[cfg(feature = "backtrace")]
@@ -158,7 +167,7 @@ impl<T> Mutex<T> {
158167
}
159168

160169
pub fn lock<'a>(&'a self) -> LockResult<MutexGuard<'a, T>> {
161-
MutexMetadata::pre_lock(&self.deps);
170+
MutexMetadata::pre_lock(&self.deps, false);
162171
self.inner.lock().map(|lock| MutexGuard { mutex: self, lock }).map_err(|_| ())
163172
}
164173

@@ -171,54 +180,109 @@ impl<T> Mutex<T> {
171180
}
172181
}
173182

174-
pub struct RwLock<T: ?Sized> {
175-
inner: StdRwLock<T>
183+
pub struct RwLock<T: Sized> {
184+
inner: StdRwLock<T>,
185+
deps: Arc<MutexMetadata>,
176186
}
177187

178-
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
188+
pub struct RwLockReadGuard<'a, T: Sized + 'a> {
189+
mutex: &'a RwLock<T>,
179190
lock: StdRwLockReadGuard<'a, T>,
180191
}
181192

182-
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
193+
pub struct RwLockWriteGuard<'a, T: Sized + 'a> {
194+
mutex: &'a RwLock<T>,
183195
lock: StdRwLockWriteGuard<'a, T>,
184196
}
185197

186-
impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
198+
impl<T: Sized> Deref for RwLockReadGuard<'_, T> {
187199
type Target = T;
188200

189201
fn deref(&self) -> &T {
190202
&self.lock.deref()
191203
}
192204
}
193205

194-
impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
206+
impl<T: Sized> Drop for RwLockReadGuard<'_, T> {
207+
fn drop(&mut self) {
208+
MUTEXES_HELD.with(|held| {
209+
held.borrow_mut().remove(&self.mutex.deps);
210+
});
211+
}
212+
}
213+
214+
impl<T: Sized> Deref for RwLockWriteGuard<'_, T> {
195215
type Target = T;
196216

197217
fn deref(&self) -> &T {
198218
&self.lock.deref()
199219
}
200220
}
201221

202-
impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
222+
impl<T: Sized> Drop for RwLockWriteGuard<'_, T> {
223+
fn drop(&mut self) {
224+
MUTEXES_HELD.with(|held| {
225+
held.borrow_mut().remove(&self.mutex.deps);
226+
});
227+
}
228+
}
229+
230+
impl<T: Sized> DerefMut for RwLockWriteGuard<'_, T> {
203231
fn deref_mut(&mut self) -> &mut T {
204232
self.lock.deref_mut()
205233
}
206234
}
207235

208236
impl<T> RwLock<T> {
209237
pub fn new(inner: T) -> RwLock<T> {
210-
RwLock { inner: StdRwLock::new(inner) }
238+
RwLock { inner: StdRwLock::new(inner), deps: Arc::new(MutexMetadata::new()) }
211239
}
212240

213241
pub fn read<'a>(&'a self) -> LockResult<RwLockReadGuard<'a, T>> {
214-
self.inner.read().map(|lock| RwLockReadGuard { lock }).map_err(|_| ())
242+
MutexMetadata::pre_lock(&self.deps, true);
243+
self.inner.read().map(|lock| RwLockReadGuard { mutex: self, lock }).map_err(|_| ())
215244
}
216245

217246
pub fn write<'a>(&'a self) -> LockResult<RwLockWriteGuard<'a, T>> {
218-
self.inner.write().map(|lock| RwLockWriteGuard { lock }).map_err(|_| ())
247+
MutexMetadata::pre_lock(&self.deps, false);
248+
self.inner.write().map(|lock| RwLockWriteGuard { mutex: self, lock }).map_err(|_| ())
219249
}
220250

221251
pub fn try_write<'a>(&'a self) -> LockResult<RwLockWriteGuard<'a, T>> {
222-
self.inner.try_write().map(|lock| RwLockWriteGuard { lock }).map_err(|_| ())
252+
let res = self.inner.try_write().map(|lock| RwLockWriteGuard { mutex: self, lock }).map_err(|_| ());
253+
if res.is_ok() {
254+
MutexMetadata::try_locked(&self.deps);
255+
}
256+
res
257+
}
258+
}
259+
260+
#[test]
261+
#[should_panic]
262+
fn recursive_lock_fail() {
263+
let mutex = Mutex::new(());
264+
let _a = mutex.lock().unwrap();
265+
let _b = mutex.lock().unwrap();
266+
}
267+
268+
#[test]
269+
fn recursive_read() {
270+
let mutex = RwLock::new(());
271+
let _a = mutex.read().unwrap();
272+
let _b = mutex.read().unwrap();
273+
}
274+
275+
#[test]
276+
#[should_panic]
277+
fn lockorder_fail() {
278+
let a = Mutex::new(());
279+
let b = Mutex::new(());
280+
{
281+
let _a = a.lock().unwrap();
282+
let _b = b.lock().unwrap();
283+
}
284+
{
285+
let _b = b.lock().unwrap();
286+
let _a = a.lock().unwrap();
223287
}
224288
}

0 commit comments

Comments
 (0)