From 8997564a0f7d3e09e66b47751238231855fb135e Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Sat, 24 Oct 2026 00:43:34 -0700 Subject: [PATCH] mgs: pause without catching the game thread inside printf freeze() suspends the live PSX thread wherever it is. While the game boots it is not idle and prints a lot, so opening the pause menu in the first second could suspend it inside printf, holding stdout's lock; the cart's next log line (Cart::screenshot) then waited for it forever and the device hung on the pause. The thread is now suspended while this task holds stdout's and stderr's locks, so it is either outside stdio or waiting for the lock (and takes it after the resume). Reproduced by opening the menu on MGS's first frame (8 ms after the game's main()): hung, and a core dump showed mgs_th suspended in printf("TASK START...") and main blocked in __flockfile(stdout). With the fix, a 25 minute run opening the menu on every game's first frame and then every 4 s did not hang. Co-Authored-By: Claude Opus 5.5 (1M context) --- components/mgs/src/mgs.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/mgs/src/mgs.cpp b/components/mgs/src/mgs.cpp index 4c3c374..2921674 100644 --- a/components/mgs/src/mgs.cpp +++ b/components/mgs/src/mgs.cpp @@ -171,7 +171,15 @@ void freeze() { if (!(mts_active_task_800C0DB0 == MTS_TASK_IDLE && psyz_critical_depth == 0)) { wait_for_idle(200); } + // the running thread is suspended wherever it is: holding stdout's and + // stderr's locks meanwhile keeps that from being inside printf (the game + // prints a lot while it boots), where it would keep the lock and the next + // log line from any other task would wait forever + flockfile(stdout); + flockfile(stderr); Mgs_ThreadsPause(); + funlockfile(stderr); + funlockfile(stdout); if (mts_active_task_800C0DB0 != MTS_TASK_IDLE) { logger.warn("frozen with mts task {} active (not idle)", mts_active_task_800C0DB0); }