From a49f4523cb14ed130e6eb3c7fa066499a2974f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 15 Aug 2026 23:17:28 +0200 Subject: [PATCH] Correct when we process the stepping queue. Also, the jitLock mutex is no longer needed. --- Core/Core.cpp | 10 +++++----- Core/Debugger/WebSocket/MemorySubscriber.cpp | 5 ++--- Core/MIPS/JitCommon/JitCommon.cpp | 5 +---- Core/MIPS/JitCommon/JitCommon.h | 2 -- Core/MIPS/MIPS.cpp | 15 +++------------ Core/MemFault.cpp | 3 --- Core/SaveState.cpp | 1 - UI/CwCheatScreen.cpp | 2 -- UI/JitCompareScreen.cpp | 2 -- UI/MiscScreens.cpp | 1 - UI/NativeApp.cpp | 10 ++++------ Windows/Debugger/DumpMemoryWindow.cpp | 1 - Windows/MainWindow.cpp | 15 +++++++++------ 13 files changed, 24 insertions(+), 48 deletions(-) diff --git a/Core/Core.cpp b/Core/Core.cpp index 96a5fc3284..9ce6cefcfe 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -301,11 +301,6 @@ bool Core_GetPowerSaving() { void Core_RunLoopUntil(u64 globalticks) { while (true) { - // Drain any functions queued up by Core_RunOnCPUThread() from other threads. Doing this at the - // top of this loop means it's reached at least once per call (i.e. about once per host frame) - // even while the CPU is fully running, and continuously (in a tight spin) while it's stepping/paused. - Core_ProcessCPUQueue(); - switch (coreState) { case CORE_POWERDOWN: case CORE_RUNTIME_ERROR: @@ -467,6 +462,11 @@ static void Core_PerformCPUStep(MIPSDebugInterface *cpu, CPUStepType stepType, i static bool Core_ProcessStepping(MIPSDebugInterface *cpu) { Core_StateProcessed(); + // Drain any functions queued up by Core_RunOnCPUThread() from other threads. Doing this at the + // top of this loop means it's reached at least once per call (i.e. about once per host frame) + // even while the CPU is fully running, and continuously (in a tight spin) while it's stepping/paused. + Core_ProcessCPUQueue(); + // Check if there's any pending save state actions. SaveState::Process(); diff --git a/Core/Debugger/WebSocket/MemorySubscriber.cpp b/Core/Debugger/WebSocket/MemorySubscriber.cpp index f4da5bec95..ce56f2eeff 100644 --- a/Core/Debugger/WebSocket/MemorySubscriber.cpp +++ b/Core/Debugger/WebSocket/MemorySubscriber.cpp @@ -73,9 +73,9 @@ static AutoDisabledReplacements LockMemory(bool keepReplacements) { result.saved = true; // Okay, save so we can restore later. result.replacements = SaveAndClearReplacements(); - std::lock_guard guard(MIPSComp::jitLock); - if (MIPSComp::jit) + if (MIPSComp::jit) { result.emuhacks = MIPSComp::jit->SaveAndClearEmuHackOps(); + } } return result; } @@ -91,7 +91,6 @@ AutoDisabledReplacements::AutoDisabledReplacements(AutoDisabledReplacements &&ot AutoDisabledReplacements::~AutoDisabledReplacements() { if (saved) { - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit) MIPSComp::jit->RestoreSavedEmuHackOps(emuhacks); RestoreSavedReplacements(replacements); diff --git a/Core/MIPS/JitCommon/JitCommon.cpp b/Core/MIPS/JitCommon/JitCommon.cpp index fd53e69ad6..5be2c8ff28 100644 --- a/Core/MIPS/JitCommon/JitCommon.cpp +++ b/Core/MIPS/JitCommon/JitCommon.cpp @@ -57,7 +57,6 @@ namespace MIPSComp { JitInterface *jit; - std::recursive_mutex jitLock; void JitAt() { // TODO: We could probably check for a bad pc here, and fire an exception. Could spare us from some crashes. @@ -185,7 +184,6 @@ std::string AddAddress(const std::string &buf, uint64_t addr) { #if PPSSPP_ARCH(ARM64) || defined(DISASM_ALL) static bool Arm64SymbolCallback(char *buffer, int bufsize, uint8_t *address) { - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit) { std::string name; if (MIPSComp::jit->DescribeCodePtr(address, name)) { @@ -275,11 +273,10 @@ const char *ppsspp_resolver(struct ud*, // But these do. - // UGLY HACK because the API is terrible + // UGLY HACK because the disassembler API is terrible static char buf[128]; std::string str; - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit && MIPSComp::jit->DescribeCodePtr((u8 *)(uintptr_t)addr, str)) { *offset = 0; truncate_cpy(buf, sizeof(buf), str); diff --git a/Core/MIPS/JitCommon/JitCommon.h b/Core/MIPS/JitCommon/JitCommon.h index 1bda276367..7af1154fa5 100644 --- a/Core/MIPS/JitCommon/JitCommon.h +++ b/Core/MIPS/JitCommon/JitCommon.h @@ -17,7 +17,6 @@ #pragma once -#include #include #include @@ -170,7 +169,6 @@ namespace MIPSComp { u32 ResolveNotTakenTarget(const BranchInfo &branchInfo); extern JitInterface *jit; - extern std::recursive_mutex jitLock; void DoDummyJitState(PointerWrap &p); diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index adf6e08480..8c43e40657 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -161,7 +161,6 @@ MIPSState::~MIPSState() { } void MIPSState::Shutdown() { - std::lock_guard guard(MIPSComp::jitLock); MIPSComp::JitInterface *oldjit = MIPSComp::jit; if (oldjit) { MIPSComp::jit = nullptr; @@ -209,7 +208,6 @@ void MIPSState::Init() { memset(vcmpResult, 0, sizeof(vcmpResult)); - std::lock_guard guard(MIPSComp::jitLock); if (PSP_CoreParameter().cpuCore == CPUCore::JIT || PSP_CoreParameter().cpuCore == CPUCore::JIT_IR) { MIPSComp::jit = MIPSComp::CreateNativeJit(this, PSP_CoreParameter().cpuCore == CPUCore::JIT_IR); } else if (PSP_CoreParameter().cpuCore == CPUCore::IR_INTERPRETER) { @@ -231,12 +229,9 @@ void MIPSState::UpdateCore(CPUCore desired) { IncrementDebugCounter(DebugCounter::CPUCORE_SWITCHES); // Get rid of the old JIT first, before switching. - { - std::lock_guard guard(MIPSComp::jitLock); - if (MIPSComp::jit) { - delete MIPSComp::jit; - MIPSComp::jit = nullptr; - } + if (MIPSComp::jit) { + delete MIPSComp::jit; + MIPSComp::jit = nullptr; } PSP_CoreParameter().cpuCore = desired; @@ -264,7 +259,6 @@ void MIPSState::UpdateCore(CPUCore desired) { break; } - std::lock_guard guard(MIPSComp::jitLock); MIPSComp::jit = newjit; } @@ -356,7 +350,6 @@ int MIPSState::RunLoopUntil(u64 globalTicks) { static std::vector> pendingClears; void MIPSState::ProcessPendingClears() { - std::lock_guard guard(MIPSComp::jitLock); for (auto &p : pendingClears) { if (p.first == 0 && p.second == 0) MIPSComp::jit->ClearCache(); @@ -370,14 +363,12 @@ void MIPSState::ProcessPendingClears() { void MIPSState::InvalidateICache(u32 address, int length) { // Only really applies to jit. // Note that the backend is responsible for ensuring native code can still be returned to. - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit && length != 0) { MIPSComp::jit->InvalidateCacheAt(address, length); } } void MIPSState::ClearJitCache() { - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit) { if (coreState == CORE_RUNNING_CPU || insideJit) { pendingClears.emplace_back(0, 0); diff --git a/Core/MemFault.cpp b/Core/MemFault.cpp index 09606655c5..478b1a6c5c 100644 --- a/Core/MemFault.cpp +++ b/Core/MemFault.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include "Common/StringUtils.h" @@ -121,8 +120,6 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { SContext *context = (SContext *)ctx; const uint8_t *codePtr = (uint8_t *)(context->CTX_PC); - std::lock_guard guard(MIPSComp::jitLock); - // We set this later if we think it can be resumed from. g_lastCrashAddress = nullptr; diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index a8d0c6c630..db983922ca 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -165,7 +165,6 @@ int g_screenshotFailures; // These must be saved before copying out memory and restored after. auto savedReplacements = SaveAndClearReplacements(); if (MIPSComp::jit && p.mode == p.MODE_WRITE) { - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit) { std::vector savedBlocks; savedBlocks = MIPSComp::jit->SaveAndClearEmuHackOps(); diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index eb518028b4..efdcf97eff 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -359,7 +359,6 @@ void CwCheatScreen::onFinish(DialogResult result) { if (result != DR_BACK) // This only works for BACK here. return; - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit) { MIPSComp::jit->ClearCache(); } @@ -385,7 +384,6 @@ void CwCheatScreen::OnAddCheat(UI::EventParams ¶ms) { void CwCheatScreen::OnEditCheatFile(UI::EventParams ¶ms) { g_Config.bReloadCheats = true; - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit) { MIPSComp::jit->ClearCache(); } diff --git a/UI/JitCompareScreen.cpp b/UI/JitCompareScreen.cpp index c64c451816..5dc71a83f8 100644 --- a/UI/JitCompareScreen.cpp +++ b/UI/JitCompareScreen.cpp @@ -337,7 +337,6 @@ void JitCompareScreen::OnBlockClick(UI::EventParams &e) { } void JitCompareScreen::OnAddressChange(UI::EventParams &e) { - std::lock_guard guard(MIPSComp::jitLock); if (!MIPSComp::jit) { return; } @@ -364,7 +363,6 @@ void JitCompareScreen::OnSelectBlock(UI::EventParams &e) { } void JitCompareScreen::OnBlockAddress(UI::EventParams &e) { - std::lock_guard guard(MIPSComp::jitLock); if (!MIPSComp::jit) { return; } diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 92183556d8..8b16cb12de 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -67,7 +67,6 @@ void HandleCommonMessages(UIMessage message, const char *value, ScreenManager *m if (message == UIMessage::REQUEST_CLEAR_JIT && PSP_IsInited()) { // TODO: This seems to clearly be the wrong place to handle this. if (MIPSComp::jit) { - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit) MIPSComp::jit->ClearCache(); } diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index e715adbb2d..a99fddbcba 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -1280,12 +1280,10 @@ void NativeFrame(GraphicsContext *graphicsContext) { g_screenManager->getUIContext()->SetTintSaturation(g_Config.fUITint, g_Config.fUISaturation); - // Drain any work queued by Core_RunOnCPUThread() from other threads. Core_RunLoopUntil() - // (called from within render() below, but only while a game is actually loaded/running) - // also does this, but that path isn't reached at all outside a game - e.g. from the main - // menu - so queued work would otherwise hang forever waiting for it. See Core_ProcessCPUQueue() - // in Core.h. - Core_ProcessCPUQueue(); + if (GetUIState() != UISTATE_INGAME) { + // In case there are any cross thread requests outside the game. + Core_ProcessCPUQueue(); + } // All actual rendering (and also emulation) happens in this render() call. renderFlags = g_screenManager->Render([]() { diff --git a/Windows/Debugger/DumpMemoryWindow.cpp b/Windows/Debugger/DumpMemoryWindow.cpp index aecfb09ee4..7d03ddbc3d 100644 --- a/Windows/Debugger/DumpMemoryWindow.cpp +++ b/Windows/Debugger/DumpMemoryWindow.cpp @@ -102,7 +102,6 @@ INT_PTR CALLBACK DumpMemoryWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam, fwrite(Memory::GetPointerOrException(bp->start), 1, bp->size, output); } else { auto savedReplacements = SaveAndClearReplacements(); - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit) { auto savedBlocks = MIPSComp::jit->SaveAndClearEmuHackOps(); fwrite(Memory::GetPointerOrException(bp->start), 1, bp->size, output); diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 00ed6b8e34..000bdbb711 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -1017,22 +1017,25 @@ namespace MainWindow { return TRUE; case VERYSLEEPY_WPARAM_GETADDRINFO: - { + { + Core_RunOnCPUThread([lParam]() { + // This is called from VerySleepy, which is on a different thread than the CPU thread. + // We need to run this on the CPU thread to avoid race conditions. VerySleepy_AddrInfo *info = (VerySleepy_AddrInfo *)lParam; const u8 *ptr = (const u8 *)info->addr; std::string name; - std::lock_guard guard(MIPSComp::jitLock); if (MIPSComp::jit && MIPSComp::jit->DescribeCodePtr(ptr, name)) { swprintf_s(info->name, L"Jit::%S", name.c_str()); - return TRUE; + return; } if (gpu && gpu->DescribeCodePtr(ptr, name)) { swprintf_s(info->name, L"GPU::%S", name.c_str()); - return TRUE; + return; } - } - return FALSE; + }); + return TRUE; + } default: return FALSE;