mirror of
https://github.com/danbulant/cushy
synced 2026-06-24 17:12:11 +00:00
Fixed a possible deadlock in block_until_updated
The animation doctest randomly failed on me this morning, and I isolated it to the order of the two mutexes. There's no reason to hold the deadlock mutex for more than the check for deadlock, so I switched which mutex the condvar is synchronizing using to ensure that another thread couldn't cause a deadlock by dropping a DynamicMutexGuard while the block_until_updated thread is performing its state check.
This commit is contained in:
parent
be483a92bd
commit
e4dfd9320d
1 changed files with 6 additions and 5 deletions
11
src/value.rs
11
src/value.rs
|
|
@ -1594,16 +1594,18 @@ impl<T> DynamicReader<T> {
|
||||||
/// This function panics if this value is already locked by the current
|
/// This function panics if this value is already locked by the current
|
||||||
/// thread.
|
/// thread.
|
||||||
pub fn block_until_updated(&mut self) -> bool {
|
pub fn block_until_updated(&mut self) -> bool {
|
||||||
let mut deadlock_state = self.source.during_callback_state.lock().ignore_poison();
|
|
||||||
assert!(
|
assert!(
|
||||||
deadlock_state
|
self.source
|
||||||
|
.during_callback_state
|
||||||
|
.lock()
|
||||||
|
.ignore_poison()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(true, |state| state.locked_thread
|
.map_or(true, |state| state.locked_thread
|
||||||
!= std::thread::current().id()),
|
!= std::thread::current().id()),
|
||||||
"deadlocked"
|
"deadlocked"
|
||||||
);
|
);
|
||||||
|
let mut state = self.source.state.lock().ignore_poison();
|
||||||
loop {
|
loop {
|
||||||
let state = self.source.state.lock().ignore_poison();
|
|
||||||
if state.wrapped.generation != self.read_generation {
|
if state.wrapped.generation != self.read_generation {
|
||||||
return true;
|
return true;
|
||||||
} else if state.readers == Arc::strong_count(&self.source)
|
} else if state.readers == Arc::strong_count(&self.source)
|
||||||
|
|
@ -1611,10 +1613,9 @@ impl<T> DynamicReader<T> {
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
drop(state);
|
|
||||||
|
|
||||||
// Wait for a notification of a change, which is synch
|
// Wait for a notification of a change, which is synch
|
||||||
deadlock_state = self.source.sync.wait(deadlock_state).ignore_poison();
|
state = self.source.sync.wait(state).ignore_poison();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue