diff --git a/Core/Core.cpp b/Core/Core.cpp index d549d79c4f09..5bf679376444 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -28,22 +28,21 @@ #include "thread/threadutil.h" #include "profiler/profiler.h" +#include "Common/GraphicsContext.h" #include "Core/Core.h" #include "Core/Config.h" +#include "Core/Host.h" #include "Core/MemMap.h" #include "Core/SaveState.h" #include "Core/System.h" +#include "Core/Debugger/Breakpoints.h" #include "Core/MIPS/MIPS.h" -#include "Common/GraphicsContext.h" #ifdef _WIN32 #include "Common/CommonWindows.h" #include "Windows/InputDevice.h" #endif -#include "Host.h" - -#include "Core/Debugger/Breakpoints.h" // Time until we stop considering the core active without user input. // Should this be configurable? 2 hours currently. @@ -54,7 +53,8 @@ static std::mutex m_hStepMutex; static std::condition_variable m_InactiveCond; static std::mutex m_hInactiveMutex; static bool singleStepPending = false; -static std::set shutdownFuncs; +static int steppingCounter = 0; +static std::set shutdownFuncs; static bool windowHidden = false; static double lastActivity = 0.0; static double lastKeepAwake = 0.0; @@ -75,30 +75,19 @@ void Core_NotifyActivity() { lastActivity = time_now_d(); } -void Core_ListenShutdown(Core_ShutdownFunc func) { +void Core_ListenLifecycle(CoreLifecycleFunc func) { shutdownFuncs.insert(func); } -void Core_NotifyShutdown() { +void Core_NotifyLifecycle(CoreLifecycle stage) { for (auto it = shutdownFuncs.begin(); it != shutdownFuncs.end(); ++it) { - (*it)(); + (*it)(stage); } } -void Core_ErrorPause() { - Core_UpdateState(CORE_ERROR); -} - -void Core_Halt(const char *msg) { - Core_EnableStepping(true); - ERROR_LOG(CPU, "CPU HALTED : %s",msg); - _dbg_update_(); -} - void Core_Stop() { Core_UpdateState(CORE_POWERDOWN); - Core_NotifyShutdown(); - m_StepCond.notify_one(); + m_StepCond.notify_all(); } bool Core_IsStepping() { @@ -239,11 +228,11 @@ void Core_RunLoop(GraphicsContext *ctx) { void Core_DoSingleStep() { singleStepPending = true; - m_StepCond.notify_one(); + m_StepCond.notify_all(); } void Core_UpdateSingleStep() { - m_StepCond.notify_one(); + m_StepCond.notify_all(); } void Core_SingleStep() { @@ -253,7 +242,7 @@ void Core_SingleStep() { static inline void CoreStateProcessed() { if (coreStatePending) { coreStatePending = false; - m_InactiveCond.notify_one(); + m_InactiveCond.notify_all(); } } @@ -334,10 +323,15 @@ void Core_EnableStepping(bool step) { sleep_ms(1); host->SetDebugMode(true); Core_UpdateState(CORE_STEPPING); + steppingCounter++; } else { host->SetDebugMode(false); coreState = CORE_RUNNING; coreStatePending = false; - m_StepCond.notify_one(); + m_StepCond.notify_all(); } } + +int Core_GetSteppingCounter() { + return steppingCounter; +} diff --git a/Core/Core.h b/Core/Core.h index 9adbd6356e17..f01a9d03e8b0 100644 --- a/Core/Core.h +++ b/Core/Core.h @@ -27,21 +27,28 @@ void UpdateRunLoop(); void Core_Run(GraphicsContext *ctx); void Core_Stop(); -void Core_ErrorPause(); // For platforms that don't call Core_Run void Core_SetGraphicsContext(GraphicsContext *ctx); -void Core_RunRenderThreadFrame(); - // called from gui void Core_EnableStepping(bool step); void Core_DoSingleStep(); void Core_UpdateSingleStep(); - -typedef void (* Core_ShutdownFunc)(); -void Core_ListenShutdown(Core_ShutdownFunc func); -void Core_NotifyShutdown(); -void Core_Halt(const char *msg); +// Changes every time we enter stepping. +int Core_GetSteppingCounter(); + +enum class CoreLifecycle { + STARTING, + // Note: includes failure cases. Guaranteed call after STARTING. + START_COMPLETE, + STOPPING, + // Guaranteed call after STOPPING. + STOPPED, +}; + +typedef void (* CoreLifecycleFunc)(CoreLifecycle stage); +void Core_ListenLifecycle(CoreLifecycleFunc func); +void Core_NotifyLifecycle(CoreLifecycle stage); bool Core_IsStepping(); diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index 78ca1d2fb8c8..b3f9a9587b89 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -182,7 +182,7 @@ int RegisterEvent(const char *name, TimedCallback callback) void AntiCrashCallback(u64 userdata, int cyclesLate) { ERROR_LOG(SAVESTATE, "Savestate broken: an unregistered event was called."); - Core_Halt("invalid timing events"); + Core_EnableStepping(true); } void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback) diff --git a/Core/Debugger/DisassemblyManager.cpp b/Core/Debugger/DisassemblyManager.cpp index 4ff4c58fd3d2..77e8c917a50a 100644 --- a/Core/Debugger/DisassemblyManager.cpp +++ b/Core/Debugger/DisassemblyManager.cpp @@ -31,6 +31,7 @@ #include "Core/Debugger/DisassemblyManager.h" std::map DisassemblyManager::entries; +std::recursive_mutex DisassemblyManager::entriesLock_; DebugInterface* DisassemblyManager::cpu; int DisassemblyManager::maxParamChars = 29; @@ -149,7 +150,8 @@ void DisassemblyManager::analyze(u32 address, u32 size = 1024) if (!PSP_IsInited()) return; - auto it = findDisassemblyEntry(entries,address,false); + std::lock_guard guard(entriesLock_); + auto it = findDisassemblyEntry(entries, address, false); if (it != entries.end()) { DisassemblyEntry* entry = it->second; @@ -219,7 +221,8 @@ void DisassemblyManager::analyze(u32 address, u32 size = 1024) std::vector DisassemblyManager::getBranchLines(u32 start, u32 size) { std::vector result; - + + std::lock_guard guard(entriesLock_); auto it = findDisassemblyEntry(entries,start,false); if (it != entries.end()) { @@ -235,38 +238,39 @@ std::vector DisassemblyManager::getBranchLines(u32 start, u32 size) void DisassemblyManager::getLine(u32 address, bool insertSymbols, DisassemblyLineInfo& dest) { + std::lock_guard guard(entriesLock_); auto it = findDisassemblyEntry(entries,address,false); if (it == entries.end()) { analyze(address); it = findDisassemblyEntry(entries,address,false); + } - if (it == entries.end()) - { - if (address % 4) - dest.totalSize = ((address+3) & ~3)-address; - else - dest.totalSize = 4; - dest.name = "ERROR"; - dest.params = "Disassembly failure"; + if (it != entries.end()) { + DisassemblyEntry *entry = it->second; + if (entry->disassemble(address, dest, insertSymbols)) return; - } } - DisassemblyEntry* entry = it->second; - if (entry->disassemble(address,dest,insertSymbols)) - return; - + dest.type = DISTYPE_OTHER; + memset(&dest.info, 0, sizeof(dest.info)); + dest.info.opcodeAddress = address; if (address % 4) dest.totalSize = ((address+3) & ~3)-address; else dest.totalSize = 4; - dest.name = "ERROR"; - dest.params = "Disassembly failure"; + if (Memory::IsValidRange(address, 4)) { + dest.name = "ERROR"; + dest.params = "Disassembly failure"; + } else { + dest.name = "-"; + dest.params = ""; + } } u32 DisassemblyManager::getStartAddress(u32 address) { + std::lock_guard guard(entriesLock_); auto it = findDisassemblyEntry(entries,address,false); if (it == entries.end()) { @@ -283,6 +287,7 @@ u32 DisassemblyManager::getStartAddress(u32 address) u32 DisassemblyManager::getNthPreviousAddress(u32 address, int n) { + std::lock_guard guard(entriesLock_); while (Memory::IsValidAddress(address)) { auto it = findDisassemblyEntry(entries,address,false); @@ -311,6 +316,7 @@ u32 DisassemblyManager::getNthPreviousAddress(u32 address, int n) u32 DisassemblyManager::getNthNextAddress(u32 address, int n) { + std::lock_guard guard(entriesLock_); while (Memory::IsValidAddress(address)) { auto it = findDisassemblyEntry(entries,address,false); @@ -345,6 +351,7 @@ DisassemblyManager::~DisassemblyManager() { void DisassemblyManager::clear() { + std::lock_guard guard(entriesLock_); for (auto it = entries.begin(); it != entries.end(); it++) { delete it->second; @@ -383,11 +390,13 @@ void DisassemblyFunction::recheck() int DisassemblyFunction::getNumLines() { + std::lock_guard guard(lock_); return (int) lineAddresses.size(); } int DisassemblyFunction::getLineNum(u32 address, bool findStart) { + std::lock_guard guard(lock_); if (findStart) { int last = (int)lineAddresses.size() - 1; @@ -418,11 +427,13 @@ int DisassemblyFunction::getLineNum(u32 address, bool findStart) u32 DisassemblyFunction::getLineAddress(int line) { + std::lock_guard guard(lock_); return lineAddresses[line]; } bool DisassemblyFunction::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) { + std::lock_guard guard(lock_); auto it = findDisassemblyEntry(entries,address,false); if (it == entries.end()) return false; @@ -434,6 +445,7 @@ void DisassemblyFunction::getBranchLines(u32 start, u32 size, std::vector guard(lock_); for (size_t i = 0; i < lines.size(); i++) { BranchLine& line = lines[i]; @@ -466,6 +478,7 @@ void DisassemblyFunction::generateBranchLines() u32 end = address+size; + std::lock_guard guard(lock_); DebugInterface* cpu = DisassemblyManager::getCpu(); for (u32 funcPos = address; funcPos < end; funcPos += 4) { @@ -524,6 +537,7 @@ void DisassemblyFunction::generateBranchLines() void DisassemblyFunction::addOpcodeSequence(u32 start, u32 end) { DisassemblyOpcode* opcode = new DisassemblyOpcode(start,(end-start)/4); + std::lock_guard guard(lock_); entries[start] = opcode; for (u32 pos = start; pos < end; pos += 4) { @@ -537,18 +551,21 @@ void DisassemblyFunction::load() // gather all branch targets std::set branchTargets; - for (size_t i = 0; i < lines.size(); i++) { - switch (lines[i].type) + std::lock_guard guard(lock_); + for (size_t i = 0; i < lines.size(); i++) { - case LINE_DOWN: - branchTargets.insert(lines[i].second); - break; - case LINE_UP: - branchTargets.insert(lines[i].first); - break; - default: - break; + switch (lines[i].type) + { + case LINE_DOWN: + branchTargets.insert(lines[i].second); + break; + case LINE_UP: + branchTargets.insert(lines[i].first); + break; + default: + break; + } } } @@ -566,6 +583,7 @@ void DisassemblyFunction::load() addOpcodeSequence(opcodeSequenceStart,funcPos); DisassemblyData* data = new DisassemblyData(funcPos,g_symbolMap->GetDataSize(funcPos),g_symbolMap->GetDataType(funcPos)); + std::lock_guard guard(lock_); entries[funcPos] = data; lineAddresses.push_back(funcPos); funcPos += data->getTotalSize(); @@ -581,6 +599,7 @@ void DisassemblyFunction::load() u32 nextPos = (funcPos+3) & ~3; DisassemblyComment* comment = new DisassemblyComment(funcPos,nextPos-funcPos,".align","4"); + std::lock_guard guard(lock_); entries[funcPos] = comment; lineAddresses.push_back(funcPos); @@ -665,6 +684,7 @@ void DisassemblyFunction::load() if (opcodeSequenceStart != opAddress) addOpcodeSequence(opcodeSequenceStart,opAddress); + std::lock_guard guard(lock_); entries[opAddress] = macro; for (int i = 0; i < macro->getNumLines(); i++) { @@ -686,6 +706,7 @@ void DisassemblyFunction::load() void DisassemblyFunction::clear() { + std::lock_guard guard(lock_); for (auto it = entries.begin(); it != entries.end(); it++) { delete it->second; @@ -866,6 +887,7 @@ bool DisassemblyData::disassemble(u32 address, DisassemblyLineInfo& dest, bool i return false; } + std::lock_guard guard(lock_); auto it = lines.find(address); if (it == lines.end()) return false; @@ -877,6 +899,7 @@ bool DisassemblyData::disassemble(u32 address, DisassemblyLineInfo& dest, bool i int DisassemblyData::getLineNum(u32 address, bool findStart) { + std::lock_guard guard(lock_); auto it = lines.upper_bound(address); if (it != lines.end()) { @@ -891,6 +914,7 @@ int DisassemblyData::getLineNum(u32 address, bool findStart) void DisassemblyData::createLines() { + std::lock_guard guard(lock_); lines.clear(); lineAddresses.clear(); diff --git a/Core/Debugger/DisassemblyManager.h b/Core/Debugger/DisassemblyManager.h index 9002f1f8c10e..7d84805b01e4 100644 --- a/Core/Debugger/DisassemblyManager.h +++ b/Core/Debugger/DisassemblyManager.h @@ -17,6 +17,7 @@ #pragma once +#include #include "Common/CommonTypes.h" #include "Core/Debugger/SymbolMap.h" #include "Core/MIPS/MIPSAnalyst.h" @@ -91,6 +92,7 @@ class DisassemblyFunction: public DisassemblyEntry std::vector lines; std::map entries; std::vector lineAddresses; + std::recursive_mutex lock_; }; class DisassemblyOpcode: public DisassemblyEntry @@ -169,6 +171,7 @@ class DisassemblyData: public DisassemblyEntry DataType type; std::map lines; std::vector lineAddresses; + std::recursive_mutex lock_; }; class DisassemblyComment: public DisassemblyEntry @@ -214,6 +217,7 @@ class DisassemblyManager static int getMaxParamChars() { return maxParamChars; }; private: static std::map entries; + static std::recursive_mutex entriesLock_; static DebugInterface* cpu; static int maxParamChars; }; diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index 77e1a24113ed..2436c69bd426 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -496,10 +496,12 @@ static void __IoManagerThread() { } } -static void __IoWakeManager() { +static void __IoWakeManager(CoreLifecycle stage) { // Ping the thread so that it knows to check coreState. - ioManagerThreadEnabled = false; - ioManager.FinishEventLoop(); + if (stage == CoreLifecycle::STOPPING) { + ioManagerThreadEnabled = false; + ioManager.FinishEventLoop(); + } } static void __IoVblank() { @@ -586,7 +588,7 @@ void __IoInit() { ioManagerThreadEnabled = g_Config.bSeparateIOThread; ioManager.SetThreadEnabled(ioManagerThreadEnabled); if (ioManagerThreadEnabled) { - Core_ListenShutdown(&__IoWakeManager); + Core_ListenLifecycle(&__IoWakeManager); ioManagerThread = new std::thread(&__IoManagerThread); ioManagerThread->detach(); } diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 569f49df5a64..43e5019a66b9 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -1415,6 +1415,7 @@ namespace MIPSAnalyst { memset(&info, 0, sizeof(info)); if (!Memory::IsValidAddress(address)) { + info.opcodeAddress = address; return info; } diff --git a/Core/System.cpp b/Core/System.cpp index 92bf4c8701f8..afe1ac76ea5b 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -317,6 +317,7 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) { INFO_LOG(BOOT, "PPSSPP %s", PPSSPP_GIT_VERSION); #endif + Core_NotifyLifecycle(CoreLifecycle::STARTING); GraphicsContext *temp = coreParameter.graphicsContext; coreParameter = coreParam; if (coreParameter.graphicsContext == nullptr) { @@ -331,6 +332,7 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) { *error_string = coreParameter.errorString; bool success = coreParameter.fileToStart != ""; if (!success) { + Core_NotifyLifecycle(CoreLifecycle::START_COMPLETE); pspIsIniting = false; } return success; @@ -361,6 +363,9 @@ bool PSP_InitUpdate(std::string *error_string) { pspIsInited = GPU_IsReady(); pspIsIniting = !pspIsInited; + if (pspIsInited) { + Core_NotifyLifecycle(CoreLifecycle::START_COMPLETE); + } return pspIsInited; } @@ -386,17 +391,20 @@ void PSP_Shutdown() { return; } + // Make sure things know right away that PSP memory, etc. is going away. + pspIsQuitting = true; + if (coreState == CORE_RUNNING) + Core_UpdateState(CORE_ERROR); + #ifndef MOBILE_DEVICE if (g_Config.bFuncHashMap) { MIPSAnalyst::StoreHashMap(); } #endif - // Make sure things know right away that PSP memory, etc. is going away. - pspIsQuitting = true; - if (coreState == CORE_RUNNING) - Core_UpdateState(CORE_ERROR); - Core_NotifyShutdown(); + if (pspIsIniting) + Core_NotifyLifecycle(CoreLifecycle::START_COMPLETE); + Core_NotifyLifecycle(CoreLifecycle::STOPPING); CPU_Shutdown(); GPU_Shutdown(); g_paramSFO.Clear(); @@ -406,6 +414,7 @@ void PSP_Shutdown() { pspIsIniting = false; pspIsQuitting = false; g_Config.unloadGameConfig(); + Core_NotifyLifecycle(CoreLifecycle::STOPPED); } void PSP_BeginHostFrame() { diff --git a/GPU/Debugger/Stepping.cpp b/GPU/Debugger/Stepping.cpp index 7e4962753a09..ea93778cff42 100644 --- a/GPU/Debugger/Stepping.cpp +++ b/GPU/Debugger/Stepping.cpp @@ -67,7 +67,7 @@ static void SetPauseAction(PauseAction act, bool waitComplete = true) { pauseLock.unlock(); actionComplete = false; - pauseWait.notify_one(); + pauseWait.notify_all(); while (waitComplete && !actionComplete) { actionWait.wait(guard); } @@ -113,7 +113,7 @@ static void RunPauseAction() { } actionComplete = true; - actionWait.notify_one(); + actionWait.notify_all(); pauseAction = PAUSE_BREAK; } @@ -197,10 +197,12 @@ void ResumeFromStepping() { SetPauseAction(PAUSE_CONTINUE, false); } -void ForceUnpause() { - SetPauseAction(PAUSE_CONTINUE, false); - actionComplete = true; - actionWait.notify_one(); +void ForceUnpause(CoreLifecycle stage) { + if (stage == CoreLifecycle::STOPPING) { + SetPauseAction(PAUSE_CONTINUE, false); + actionComplete = true; + actionWait.notify_all(); + } } } // namespace diff --git a/GPU/Debugger/Stepping.h b/GPU/Debugger/Stepping.h index cb651af23428..3e9b5086ccbc 100644 --- a/GPU/Debugger/Stepping.h +++ b/GPU/Debugger/Stepping.h @@ -20,6 +20,7 @@ #include #include "Common/CommonTypes.h" +#include "Core/Core.h" #include "GPU/Common/GPUDebugInterface.h" namespace GPUStepping { @@ -37,5 +38,5 @@ namespace GPUStepping { bool GPU_SetCmdValue(u32 op); void ResumeFromStepping(); - void ForceUnpause(); + void ForceUnpause(CoreLifecycle stage); }; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index e68cf8b5d7b8..8064883adac8 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -399,15 +399,15 @@ void EmuScreen::sendMessage(const char *message, const char *value) { // In case we need to position touch controls differently. RecreateViews(); } else if (!strcmp(message, "control mapping") && screenManager()->topScreen() == this) { - UpdateUIState(UISTATE_MENU); + UpdateUIState(UISTATE_PAUSEMENU); releaseButtons(); screenManager()->push(new ControlMappingScreen()); } else if (!strcmp(message, "display layout editor") && screenManager()->topScreen() == this) { - UpdateUIState(UISTATE_MENU); + UpdateUIState(UISTATE_PAUSEMENU); releaseButtons(); screenManager()->push(new DisplayLayoutScreen()); } else if (!strcmp(message, "settings") && screenManager()->topScreen() == this) { - UpdateUIState(UISTATE_MENU); + UpdateUIState(UISTATE_PAUSEMENU); releaseButtons(); screenManager()->push(new GameSettingsScreen(gamePath_)); } else if (!strcmp(message, "gpu dump next frame")) { diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 2b1639971f7e..e77238ba3b94 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -67,7 +67,7 @@ void CGEDebugger::Init() { CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) : Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent) { GPUBreakpoints::Init(); - Core_ListenShutdown(ForceUnpause); + Core_ListenLifecycle(ForceUnpause); // minimum size = a little more than the default RECT windowRect;