Fixed race condition in `ResponseVar::wait_done`.
The recent change of `Var::wait_update` to an async method caused it to not instantiate the future at the moment the method is called, so the code that double checks if the response is done in `wait_done` no longer covered all conditions.
This commit is contained in:
parent
7af83f6990
commit
e092792ff6
|
@ -1,34 +1,3 @@
|
|||
* Repeatedly opening the markdown example sometimes shows blank spaces where text should be.
|
||||
- Blank spaces are the null char (0). Font was `"<empty>"` when it failed, is shaping before font load and then never updating?
|
||||
- Waiting a single font ResponseVar times-out, but the task itself of that font loading does not.
|
||||
- Bug in the response future?
|
||||
- Yes, replacing `wait_into_rsp` loop probing and sleeping *fixes* the bug.
|
||||
- Need an actual fix.
|
||||
- `WaitUpdateFut` timeout, hook never called.
|
||||
- Having trouble tracing modify (bug vanishes if there are prints).
|
||||
```
|
||||
ok:
|
||||
|
||||
!!: modify Arc(0x23dd0339870)
|
||||
!!: apply modify Arc(0x23dd0339870)
|
||||
!!: modify Arc(0x23dd0339ab0)
|
||||
!!: apply modify Arc(0x23dd0339ab0)
|
||||
!!: modify Arc(0x23dd0338eb0)
|
||||
!!: apply modify Arc(0x23dd0338eb0)
|
||||
!!: modify Arc(0x23dd0339630)
|
||||
!!: apply modify Arc(0x23dd0339630)
|
||||
|
||||
timeout:
|
||||
|
||||
!!: modify Arc(0x23dfa6a1da0)
|
||||
!!: apply modify Arc(0x23dfa6a1da0)
|
||||
!!: modify Arc(0x23dfa6a2340)
|
||||
!!: modify Arc(0x23dfa6a2520)
|
||||
!!: apply modify Arc(0x23dfa6a2340)
|
||||
!!: apply modify Arc(0x23dfa6a2520)
|
||||
!!: TIMEOUT Arc(0x23dfa6a2520)
|
||||
```
|
||||
|
||||
* `StyleMix` does not capture `extend_style`/`replace_style` on the same widget, so it ends-up ignored. Need
|
||||
to promote this pattern.
|
||||
|
||||
|
|
|
@ -1258,7 +1258,7 @@ mod response {
|
|||
fn race_condition() {
|
||||
let mut app = APP.minimal().run_headless(false);
|
||||
|
||||
for _ in 0..1000 {
|
||||
for _ in 0..100 {
|
||||
let a = task::respond(async {
|
||||
task::deadline(1.ms()).await;
|
||||
'a'
|
||||
|
|
|
@ -1182,14 +1182,16 @@ pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
|
|||
/// in sync with the UI, but it will elapse in any thread when the variable updates after the future is instantiated.
|
||||
///
|
||||
/// Note that outside of the UI tree there is no variable synchronization across multiple var method calls, so
|
||||
/// a sequence of `get(); wait_is_new().await; get();` can miss a value between `get` and `wait_is_new`.
|
||||
/// a sequence of `get(); wait_is_new().await; get();` can miss a value between `get` and `wait_update`. The returned
|
||||
/// future captures the [`last_update`] at the moment this method is called, this can be leveraged by *double-checking* to
|
||||
/// avoid race conditions, see the [`wait_value`] default implementation for more details.
|
||||
///
|
||||
/// [`get`]: Var::get
|
||||
/// [`wait_value`]: Var::wait_value
|
||||
/// [`last_update`]: AnyVar::last_update
|
||||
/// [`is_new`]: AnyVar::is_new
|
||||
#[allow(async_fn_in_trait)]
|
||||
async fn wait_update(&self) -> VarUpdateId {
|
||||
crate::future::WaitUpdateFut::new(self).await
|
||||
fn wait_update(&self) -> impl std::future::Future<Output = VarUpdateId> {
|
||||
crate::future::WaitUpdateFut::new(self)
|
||||
}
|
||||
|
||||
/// Awaits for [`is_animating`] to change from `true` to `false`.
|
||||
|
@ -1200,9 +1202,20 @@ pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
|
|||
/// If the variable does have the [`VarCapabilities::NEW`] the future is always ready.
|
||||
///
|
||||
/// [`is_animating`]: AnyVar::is_animating
|
||||
fn wait_animation(&self) -> impl std::future::Future<Output = ()> {
|
||||
crate::future::WaitIsNotAnimatingFut::new(self)
|
||||
}
|
||||
|
||||
///Awaits for a value that passes the `predicate`.
|
||||
#[allow(async_fn_in_trait)]
|
||||
async fn wait_animation(&self) {
|
||||
crate::future::WaitIsNotAnimatingFut::new(self).await
|
||||
async fn wait_value(&self, mut predicate: impl FnMut(&T) -> bool) {
|
||||
while !self.with(&mut predicate) {
|
||||
let future = self.wait_update();
|
||||
if self.with(&mut predicate) {
|
||||
break;
|
||||
}
|
||||
future.await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Visit the current value of the variable, if it [`is_new`].
|
||||
|
|
|
@ -128,13 +128,7 @@ impl<T: VarValue> ResponseVar<T> {
|
|||
///
|
||||
/// [`rsp`]: Self::rsp
|
||||
pub async fn wait_done(&self) {
|
||||
while !self.is_done() {
|
||||
let w = self.wait_update();
|
||||
if self.is_done() {
|
||||
break;
|
||||
}
|
||||
w.await;
|
||||
}
|
||||
self.wait_value(Response::is_done).await
|
||||
}
|
||||
|
||||
/// Clone the response, if present and new.
|
||||
|
|
Loading…
Reference in New Issue