Fix PinMAME busy-wait freeze on browser/window focus loss
core.vbs auto-wires Controller.Pause = True into every table's Paused
event, which Player::OnFocusChanged() fires on focus loss. PinMAME's
own pause handling in usrintrf.c is a "while (g_fPause) { ...;
draw_screen(); ... }" busy-wait written for a real-OS-thread host,
where a separate thread later flips g_fPause back to 0. Under our
single-threaded Emscripten cooperative-scheduling model there is no
second thread to clear it, so entering that loop spins forever at
100% CPU with the tab completely unresponsive.
cpu_run_emscripten_step() now checks g_fPause up front and skips
cpu_timeslice() (and therefore that loop) entirely while paused;
emulation simply doesn't advance until Controller.Pause is set back
to False and the step function is called again next frame.
Confirmed fixed by hands-on testing: unfocusing the browser during a
PinMAME ROM session no longer freezes the tab.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/src/cpuexec.c b/src/cpuexec.c
|
diff --git a/src/cpuexec.c b/src/cpuexec.c
|
||||||
index 07db6a1..0bfcbe7 100644
|
index 07db6a1..19da31a 100644
|
||||||
--- a/src/cpuexec.c
|
--- a/src/cpuexec.c
|
||||||
+++ b/src/cpuexec.c
|
+++ b/src/cpuexec.c
|
||||||
@@ -466,6 +466,65 @@ void cpu_run(void)
|
@@ -466,6 +466,78 @@ void cpu_run(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,6 +29,19 @@ index 07db6a1..0bfcbe7 100644
|
|||||||
+ once it has fully quit (cpu_post_run() has already been invoked). */
|
+ once it has fully quit (cpu_post_run() has already been invoked). */
|
||||||
+int cpu_run_emscripten_step(void)
|
+int cpu_run_emscripten_step(void)
|
||||||
+{
|
+{
|
||||||
|
+ /* usrintrf.c's per-frame video update contains a "while (g_fPause) {
|
||||||
|
+ ...; draw_screen(); ... }" busy-wait (see the VPINMAME/LIBPINMAME
|
||||||
|
+ branch around updatescreen()) that assumes a real OS thread will
|
||||||
|
+ later flip g_fPause back to 0 from outside it. We're single-threaded
|
||||||
|
+ here, so entering that loop at all would spin forever burning 100%
|
||||||
|
+ CPU with no way out - nothing else can ever run to clear the flag.
|
||||||
|
+ Skip cpu_timeslice() (and therefore that loop) entirely while paused;
|
||||||
|
+ the emulation simply doesn't advance until Controller.Pause is set
|
||||||
|
+ back to False and this function is called again next frame. */
|
||||||
|
+ extern int g_fPause;
|
||||||
|
+ if (g_fPause)
|
||||||
|
+ return 1;
|
||||||
|
+
|
||||||
+ const double frame_target = timer_get_time() + (1.0 / 60.0);
|
+ const double frame_target = timer_get_time() + (1.0 / 60.0);
|
||||||
+
|
+
|
||||||
+ while (!time_to_quit && !time_to_reset && timer_get_time() < frame_target)
|
+ while (!time_to_quit && !time_to_reset && timer_get_time() < frame_target)
|
||||||
|
|||||||
Reference in New Issue
Block a user