Close the progress dialog when work is complete but its text is held

The progress dialog server only leaves its loop when the counters match AND
g_progr_text is empty. That text is refcounted across nested progress scopes, so
a leaked reference leaves the loop spinning forever: the dialog is never closed,
and the cleanup that resets g_progr_ptotal never runs either, which is what
ppu_thread::cpu_task waits on before switching to overlay-message mode.

Seen on device with a fully booted, running game sitting behind a "Building SPU
Cache... 941 of 941" dialog for over ten minutes. The RSX thread and two SPU
threads were at 97%, syscall counters were climbing, and nothing had compiled
since six minutes in. Note the label is stale in that state: the server only
overwrites its cached text when it receives a non-empty one, so the last
meaningful message stays on screen and says nothing about which scope leaked.

Closes the dialog once the counters are complete and have been completely idle
for roughly five seconds. wait_no_update_count resets on any change to any
counter or to the text, so work in progress can never reach the threshold. The
warning names the held text, which is what will identify the leaking scope.

This is a safety net. The reference leak itself is still there.
This commit is contained in:
jpolo1224
2026-08-06 23:34:25 -04:00
parent 2c06abaf57
commit f04aa0e823
+22
View File
@@ -384,6 +384,28 @@ void progress_dialog_server::operator()()
break;
}
// Watchdog: all work is accounted for, but the progress TEXT is still held.
//
// g_progr_text is refcounted across nested scoped_progress_dialog scopes, and a
// leaked reference leaves this loop spinning forever: the dialog is never closed
// and the cleanup below never runs, so g_progr_ptotal also never returns to 0 --
// which is what ppu_thread::cpu_task waits on before switching to overlay-message
// mode. Observed on Android with a booted, running game sitting behind a
// "Building SPU Cache... 941 of 941" dialog for 10+ minutes with nothing left to
// compile.
//
// Safe because it is gated on the counters being COMPLETE and completely idle:
// wait_no_update_count resets on any change to any counter or to the text, so
// real work in progress can never reach this threshold. 500 * 10ms = ~5s, well
// under the 20s force-update that also resets the counter.
if (ftotal == fdone && ptotal == pdone && wait_no_update_count >= 500)
{
sys_log.warning("Progress dialog: closing after %u idle polls with a held "
"text reference (f:%u/%u p:%u/%u, text='%s')",
wait_no_update_count, fdone, ftotal, pdone, ptotal, text1);
break;
}
sleep_for = 10'000;
wait_no_update_count++;
}