make progress updates fail gracefully on server queue full

Progress updates can come at a right too high for the renderer
to keep up, so instead of deadlocking, we discard update messages
that are too frequent.
This commit is contained in:
bunnie 2022-04-08 18:55:56 +08:00
parent 3ef2dae2f0
commit 3f962b6bb0
3 changed files with 37 additions and 35 deletions

View file

@ -81,7 +81,7 @@ pub(crate) enum Opcode {
/// raise a progress bar
StartProgress,
/// update the progress bar
UpdateProgress,
DoUpdateProgress,
/// lower a progress bar
StopProgress,
/// update a dynamic notification's text
@ -99,7 +99,6 @@ pub(crate) enum Opcode {
// box because it's a convenience routine used by "everyone"; password boxes are always handled within
// a given secured server so that the attack surface for these do not extend into the modals boundary.
InitiateOp,
DoUpdateProgress,
FinishProgress,
TextEntryReturn,

View file

@ -111,9 +111,17 @@ impl Modals {
/// but, progress updates are meant to be fast and frequent, and generally if a progress bar shows
/// something whacky it's not going to affect a security outcome
pub fn update_progress(&self, current: u32) -> Result<(), xous::Error> {
send_message(self.conn,
Message::new_scalar(Opcode::UpdateProgress.to_usize().unwrap(), current as usize, 0, 0, 0)
).expect("couldn't update progress");
match xous::try_send_message(self.conn,
Message::new_scalar(Opcode::DoUpdateProgress.to_usize().unwrap(), current as usize, 0, 0, 0)
) {
Ok(_) => (),
Err(e) => {
log::warn!("update_progress failed with {:?}, skipping request", e);
// most likely issue is that the server queue is overfull because too many progress updates were sent
// sleep the sending thread to rate-limit requests, while discarding the current request.
xous::yield_slice()
}
}
Ok(())
}

View file

@ -224,12 +224,6 @@ fn xmain() -> ! {
Message::new_scalar(Opcode::InitiateOp.to_usize().unwrap(), 0, 0, 0, 0)
).expect("couldn't initiate UX op");
},
Some(Opcode::UpdateProgress) => msg_scalar_unpack!(msg, current, _, _, _, {
send_message(
renderer_cid,
Message::new_scalar(Opcode::DoUpdateProgress.to_usize().unwrap(), current, 0, 0, 0)
).expect("couldn't update progress bar");
}),
Some(Opcode::StopProgress) => msg_scalar_unpack!(msg, t0, t1, t2, t3, {
let token = [t0 as u32, t1 as u32, t2 as u32, t3 as u32];
if token != token_lock.unwrap_or(default_nonce) {
@ -289,6 +283,30 @@ fn xmain() -> ! {
Message::new_scalar(Opcode::DoCloseDynamicNotification.to_usize().unwrap(), 0, 0, 0, 0)
).expect("couldn't close dynamic notification");
}),
// this got promoted to an external API during the deferred response refactor to eliminate an intermediate state
Some(Opcode::DoUpdateProgress) => msg_scalar_unpack!(msg, current, _, _, _, {
let new_percentage = compute_checked_percentage(
current as u32, start_work, end_work);
log::trace!("percentage: {}, current: {}, start: {}, end: {}", new_percentage, current, start_work, end_work);
if new_percentage != last_percentage {
last_percentage = new_percentage;
progress_action.set_state(last_percentage);
#[cfg(feature="tts")]
{
if tt.elapsed_ms() - last_tick > TICK_INTERVAL {
tts.tts_blocking(t!("progress.increment", xous::LANG)).unwrap();
last_tick = tt.elapsed_ms();
}
}
renderer_modal.modify(
Some(ActionType::Slider(progress_action)),
None, false,
None, false, None
);
renderer_modal.redraw();
xous::yield_slice(); // give time for the GAM to redraw
}
}),
// ------------------ INTERNAL APIS --------------------
Some(Opcode::InitiateOp) => {
@ -394,7 +412,7 @@ fn xmain() -> ! {
#[cfg(feature="tts")]
tts.tts_simple(text.as_str().unwrap()).unwrap();
bot_text.push_str(text.as_str().unwrap());
}
}
let mut gutter = gam::modal::Notification::new(
renderer_cid,
Opcode::Gutter.to_u32().unwrap()
@ -414,29 +432,6 @@ fn xmain() -> ! {
}
}
},
Some(Opcode::DoUpdateProgress) => msg_scalar_unpack!(msg, current, _, _, _, {
let new_percentage = compute_checked_percentage(
current as u32, start_work, end_work);
log::trace!("percentage: {}, current: {}, start: {}, end: {}", new_percentage, current, start_work, end_work);
if new_percentage != last_percentage {
last_percentage = new_percentage;
progress_action.set_state(last_percentage);
#[cfg(feature="tts")]
{
if tt.elapsed_ms() - last_tick > TICK_INTERVAL {
tts.tts_blocking(t!("progress.increment", xous::LANG)).unwrap();
last_tick = tt.elapsed_ms();
}
}
renderer_modal.modify(
Some(ActionType::Slider(progress_action)),
None, false,
None, false, None
);
renderer_modal.redraw();
xous::yield_slice(); // give time for the GAM to redraw
}
}),
Some(Opcode::FinishProgress) => {
renderer_modal.gam.relinquish_focus().unwrap();
op = RendererState::None;