diff --git a/console_backend/src/settings_tab.rs b/console_backend/src/settings_tab.rs index b23ec4b74..113487b84 100644 --- a/console_backend/src/settings_tab.rs +++ b/console_backend/src/settings_tab.rs @@ -34,9 +34,14 @@ lazy_static! { pub fn start_thd(tab: &SettingsTab) { let mut recv = tab.shared_state.watch_settings_state(); - while let Ok(state) = recv.wait() { - tab.shared_state.set_settings_state(Default::default()); - tick(tab, state); + while let Ok(mut guard) = recv.wait_mut() { + let state = &mut *guard; + // taking the state reverts the settings state back to its default value + // without triggering another update (which would cause this to loop forever) + let s = std::mem::take(state); + // drop the guard so the settings state can get updated while`tick` runs (which might take a while) + drop(guard); + tick(tab, s); } } diff --git a/console_backend/src/watch.rs b/console_backend/src/watch.rs index e1cd9def5..f842c22ac 100644 --- a/console_backend/src/watch.rs +++ b/console_backend/src/watch.rs @@ -1,12 +1,12 @@ -use std::fmt; -use std::sync::atomic::AtomicUsize; -use std::sync::Weak; -use std::sync::{ - atomic::{AtomicBool, Ordering}, - Arc, +use std::{ + fmt, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, + }, }; -use parking_lot::{Condvar, Mutex}; +use parking_lot::{Condvar, MappedMutexGuard, Mutex, MutexGuard}; pub struct Watched { shared: Arc>, @@ -43,7 +43,7 @@ impl Watched { data.version }; WatchReceiver { - shared: Arc::downgrade(&self.shared), + shared: Arc::clone(&self.shared), last_seen: version.wrapping_sub(1), } } @@ -85,21 +85,25 @@ impl Drop for Watched { } pub struct WatchReceiver { - shared: Weak>, + shared: Arc>, last_seen: u64, } impl WatchReceiver { pub fn get(&mut self) -> Result { - let shared = Shared::upgrade(&self.shared)?; - let data = shared.data.lock(); + if self.shared.is_closed() { + return Err(RecvError); + } + let data = self.shared.data.lock(); self.last_seen = data.version; Ok(data.value.clone()) } pub fn get_if_new(&mut self) -> Result, RecvError> { - let shared = Shared::upgrade(&self.shared)?; - let data = shared.data.lock(); + if self.shared.is_closed() { + return Err(RecvError); + } + let data = self.shared.data.lock(); if self.last_seen == data.version { Ok(None) } else { @@ -109,18 +113,15 @@ impl WatchReceiver { } pub fn wait(&mut self) -> Result { - let shared = Shared::upgrade(&self.shared)?; - let mut data = shared.data.lock(); - while data.version == self.last_seen { - shared.on_update.wait(&mut data); - if shared.is_closed() { - return Err(RecvError); - } - } - self.last_seen = data.version; + let data = self.wait_inner()?; Ok(data.value.clone()) } + pub fn wait_mut(&mut self) -> Result, RecvError> { + let data = self.wait_inner()?; + Ok(MutexGuard::map(data, |d| &mut d.value)) + } + pub fn wait_until(&mut self, mut f: F) -> Result where F: FnMut(&T) -> bool, @@ -139,12 +140,27 @@ impl WatchReceiver { { self.wait_until(|v| !f(v)) } + + fn wait_inner(&mut self) -> Result>, RecvError> { + if self.shared.is_closed() { + return Err(RecvError); + } + let mut data = self.shared.data.lock(); + while data.version == self.last_seen { + self.shared.on_update.wait(&mut data); + if self.shared.is_closed() { + return Err(RecvError); + } + } + self.last_seen = data.version; + Ok(data) + } } impl Clone for WatchReceiver { fn clone(&self) -> WatchReceiver { WatchReceiver { - shared: Weak::clone(&self.shared), + shared: Arc::clone(&self.shared), last_seen: self.last_seen, } } @@ -166,15 +182,6 @@ impl Shared { fn is_closed(&self) -> bool { self.closed.load(Ordering::SeqCst) } - - fn upgrade(me: &Weak) -> Result, RecvError> { - let shared = me.upgrade().ok_or(RecvError)?; - if shared.is_closed() { - Err(RecvError) - } else { - Ok(shared) - } - } } struct Value {