Legacy Win32 debugger: fix the painting problem with a frame-scoped mutex

Debugger windows (register list, disassembly view, memory view, breakpoint/
thread/module/stack lists, watch list) read CPU-thread-owned state directly
from the GUI thread's WM_PAINT/list-fill handlers, racing against the CPU
thread. Routing every read through Core_RunOnCPUThread would be too slow for
something invoked continuously on paint/list-refresh.

Add g_frameMutex (Core.h/Core.cpp), held by NativeFrame() only across the
span where it actually touches that state (running the CPU, processing
breakpoints, running the ImGui debugger) - not across input handling or the
present/frame-pacing waits. Debugger windows now hold the same mutex while
reading, giving synchronized reads without the round-trip cost of queuing
to the CPU thread.

CtrlRegisterList::onPaint() goes back to always reading live values (now
safe under the lock) and grays them out by color alone while the core is
running, rather than the earlier snapshot-caching approach.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
This commit is contained in:
Henrik Rydgård
2026-08-08 17:22:12 +02:00
co-authored by Claude Sonnet 5
parent 03dcfd3931
commit f72709feb0
10 changed files with 129 additions and 38 deletions
+4
View File
@@ -129,6 +129,10 @@ static void Core_ProcessCPUQueue() {
g_cpuQueueCond.notify_all();
}
// See Core.h for the rationale. Held by NativeFrame() (in NativeApp.cpp) around the span where it
// actually touches CPU-thread-owned debugger state.
std::mutex g_frameMutex;
// This is so that external threads can wait for the CPU to become inactive.
static std::condition_variable m_InactiveCond;
static std::mutex m_hInactiveMutex;