From 1dcc6b8026a1cce5aae75150af4256c267153fb8 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Tue, 17 Jun 2025 07:21:35 +0900 Subject: [PATCH] fix: Prevent false-positive deadlocks on try_lock --- src/rt/mutex.rs | 3 +++ src/rt/rwlock.rs | 6 ++++++ tests/mutex.rs | 18 ++++++++++++++++++ tests/rwlock.rs | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+) diff --git a/src/rt/mutex.rs b/src/rt/mutex.rs index f2e12701..427bafb5 100644 --- a/src/rt/mutex.rs +++ b/src/rt/mutex.rs @@ -47,6 +47,9 @@ impl Mutex { } pub(crate) fn try_acquire_lock(&self, location: Location) -> bool { + if self.is_locked() { + return false; + } self.state.branch_opaque(location); self.post_acquire() } diff --git a/src/rt/rwlock.rs b/src/rt/rwlock.rs index cd8ec9b9..23639e24 100644 --- a/src/rt/rwlock.rs +++ b/src/rt/rwlock.rs @@ -79,11 +79,17 @@ impl RwLock { } pub(crate) fn try_acquire_read_lock(&self, location: Location) -> bool { + if self.is_write_locked() { + return false; + } self.state.branch_action(Action::Read, location); self.post_acquire_read_lock() } pub(crate) fn try_acquire_write_lock(&self, location: Location) -> bool { + if self.is_write_locked() || self.is_read_locked() { + return false; + } self.state.branch_action(Action::Write, location); self.post_acquire_write_lock() } diff --git a/tests/mutex.rs b/tests/mutex.rs index fdb3f4bf..905950a7 100644 --- a/tests/mutex.rs +++ b/tests/mutex.rs @@ -91,3 +91,21 @@ fn mutex_into_inner() { assert_eq!(lock, 2); }) } + +#[test] +fn try_lock_no_block() { + loom::model(|| { + let lock = Rc::new(Mutex::new(0)); + let lock2 = lock.clone(); + + let th = thread::spawn(move || { + let _ = lock.try_lock(); + }); + + let guard = lock2.try_lock(); + + th.join().unwrap(); + + drop(guard) + }) +} diff --git a/tests/rwlock.rs b/tests/rwlock.rs index 1ca6728a..37495321 100644 --- a/tests/rwlock.rs +++ b/tests/rwlock.rs @@ -162,3 +162,21 @@ fn rwlock_into_inner() { assert_eq!(lock, 2); }) } + +#[test] +fn rwlock_try_write_no_block() { + loom::model(|| { + let lock = Rc::new(RwLock::new(0)); + let lock2 = lock.clone(); + + let th = thread::spawn(move || { + let _ = lock.try_read(); + }); + + let guard = lock2.try_write(); + + th.join().unwrap(); + + drop(guard) + }) +}