Add strategic backoff in WinRT backend to (hopefully) eliminate a deadlock.

This commit is contained in:
Nolan Darilek 2020-12-07 14:58:59 -06:00
parent 49e8c0e5dc
commit a905439d9c
3 changed files with 31 additions and 8 deletions

View File

@ -16,6 +16,7 @@ crate-type = ["lib", "cdylib", "staticlib"]
use_tolk = ["tolk"] use_tolk = ["tolk"]
[dependencies] [dependencies]
backoff = "0.2"
dyn-clonable = "0.9" dyn-clonable = "0.9"
lazy_static = "1" lazy_static = "1"
log = "0.4" log = "0.4"

View File

@ -1,7 +1,8 @@
#[cfg(windows)]
use std::collections::HashMap;
use std::sync::Mutex; use std::sync::Mutex;
#[cfg(windows)]
use std::{collections::HashMap, time::Duration};
use backoff::{ExponentialBackoff, Operation};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::{info, trace}; use log::{info, trace};
use winrt::*; use winrt::*;
@ -133,6 +134,13 @@ impl WinRT {
playback_list, playback_list,
}) })
} }
fn backoff(&self) -> ExponentialBackoff {
ExponentialBackoff {
initial_interval: Duration::from_millis(3),
..Default::default()
}
}
} }
impl Backend for WinRT { impl Backend for WinRT {
@ -167,12 +175,18 @@ impl Backend for WinRT {
if self.player.playback_session()?.playback_state()? != MediaPlaybackState::Playing { if self.player.playback_session()?.playback_state()? != MediaPlaybackState::Playing {
self.player.play()?; self.player.play()?;
} }
let mut uid = NEXT_UTTERANCE_ID.lock().unwrap(); let mut op = || {
let utterance_id = UtteranceId::WinRT(*uid); let mut uid = NEXT_UTTERANCE_ID.try_lock()?;
*uid += 1; let utterance_id = UtteranceId::WinRT(*uid);
drop(uid); *uid += 1;
let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap(); Ok(utterance_id)
mappings.push((self.id, item, utterance_id)); };
let mut backoff = self.backoff();
let utterance_id = op.retry(&mut backoff)?;
{
let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap();
mappings.push((self.id, item, utterance_id));
}
Ok(Some(utterance_id)) Ok(Some(utterance_id))
} }

View File

@ -99,6 +99,8 @@ impl Default for Features {
pub enum Error { pub enum Error {
#[error("IO error: {0}")] #[error("IO error: {0}")]
IO(#[from] std::io::Error), IO(#[from] std::io::Error),
#[error("Backoff error")]
Backoff,
#[error("Value not received")] #[error("Value not received")]
NoneError, NoneError,
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
@ -113,6 +115,12 @@ pub enum Error {
OutOfRange, OutOfRange,
} }
impl<E> From<backoff::Error<E>> for Error {
fn from(_: backoff::Error<E>) -> Self {
Error::Backoff
}
}
#[clonable] #[clonable]
trait Backend: Clone + std::fmt::Debug { trait Backend: Clone + std::fmt::Debug {
fn id(&self) -> Option<BackendId>; fn id(&self) -> Option<BackendId>;