mirror of
https://github.com/danbulant/cushy
synced 2026-07-05 11:10:34 +00:00
Allowing change callbacks to recurse still
The last fix had a panic where a guard should have been allowed to be created. Change callbacks detect when they are about to be fired from themselves, and prevent the deadlock.
This commit is contained in:
parent
e54bbd743d
commit
2045d5fb4a
1 changed files with 13 additions and 10 deletions
23
src/value.rs
23
src/value.rs
|
|
@ -1227,7 +1227,7 @@ impl<T> Dynamic<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lock_inner<const READONLY: bool>(&self) -> DynamicGuard<'_, T, READONLY> {
|
fn lock_inner<const READONLY: bool>(&self) -> DynamicGuard<'_, T, READONLY> {
|
||||||
let guard = self.0.state().expect("deadlocked");
|
let mut guard = self.0.state().expect("deadlocked");
|
||||||
// Before allowing a lock, we need to ensure that the current change
|
// Before allowing a lock, we need to ensure that the current change
|
||||||
// callbacks aren't executing. Otherwise, during drop of this guard, if
|
// callbacks aren't executing. Otherwise, during drop of this guard, if
|
||||||
// we notify of changes from a second thread than one set is already
|
// we notify of changes from a second thread than one set is already
|
||||||
|
|
@ -1235,16 +1235,19 @@ impl<T> Dynamic<T> {
|
||||||
// other and deadlocking. By ensuring a single guard and change
|
// other and deadlocking. By ensuring a single guard and change
|
||||||
// callbacks cycle can exist at any one time, we prevent this deadlock.
|
// callbacks cycle can exist at any one time, we prevent this deadlock.
|
||||||
if !READONLY && guard.callbacks.currently_executing.lock().thread.is_some() {
|
if !READONLY && guard.callbacks.currently_executing.lock().thread.is_some() {
|
||||||
let current_thread_id = std::thread::current().id();
|
|
||||||
let callbacks = guard.callbacks.clone();
|
let callbacks = guard.callbacks.clone();
|
||||||
let mut executing = callbacks.currently_executing.lock();
|
guard.unlocked(|| {
|
||||||
loop {
|
let current_thread_id = std::thread::current().id();
|
||||||
match &executing.thread {
|
let mut executing = callbacks.currently_executing.lock();
|
||||||
Some(th) if th == ¤t_thread_id => panic!("deadlocked"),
|
|
||||||
Some(_) => callbacks.sync.wait(&mut executing),
|
loop {
|
||||||
None => break,
|
match &executing.thread {
|
||||||
};
|
Some(th) if th == ¤t_thread_id => break,
|
||||||
}
|
None => break,
|
||||||
|
Some(_) => callbacks.sync.wait(&mut executing),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
DynamicGuard {
|
DynamicGuard {
|
||||||
guard: DynamicOrOwnedGuard::Dynamic(guard),
|
guard: DynamicOrOwnedGuard::Dynamic(guard),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue