Permalink
Browse files

Core: Refactor stepping and locking.

This should fix some race conditions with the cond vars.
  • Loading branch information...
unknownbrackets committed Apr 30, 2018
1 parent 6bf6490 commit c15ade3b1be7ac833d63aae5e5e15d36bfc86f32
Showing with 40 additions and 35 deletions.
  1. +38 −33 Core/Core.cpp
  2. +2 −0 Core/Core.h
  3. +0 −2 Core/Host.h
View
@@ -87,7 +87,6 @@ void Core_NotifyLifecycle(CoreLifecycle stage) {
void Core_Stop() {
Core_UpdateState(CORE_POWERDOWN);
m_StepCond.notify_all();
}
bool Core_IsStepping() {
@@ -173,6 +172,7 @@ bool UpdateScreenScale(int width, int height) {
return false;
}
// Note: not used on Android.
void UpdateRunLoop() {
if (windowHidden && g_Config.bPauseWhenMinimized) {
sleep_ms(16);
@@ -227,11 +227,13 @@ void Core_RunLoop(GraphicsContext *ctx) {
}
void Core_DoSingleStep() {
std::lock_guard<std::mutex> guard(m_hStepMutex);
singleStepPending = true;
m_StepCond.notify_all();
}
void Core_UpdateSingleStep() {
std::lock_guard<std::mutex> guard(m_hStepMutex);
m_StepCond.notify_all();
}
@@ -241,17 +243,49 @@ void Core_SingleStep() {
static inline void CoreStateProcessed() {
if (coreStatePending) {
std::lock_guard<std::mutex> guard(m_hInactiveMutex);
coreStatePending = false;
m_InactiveCond.notify_all();
}
}
static inline void Core_WaitStepping() {
std::unique_lock<std::mutex> guard(m_hStepMutex);
if (!singleStepPending && coreState == CORE_STEPPING)
m_StepCond.wait(guard);
}
void Core_ProcessStepping() {
CoreStateProcessed();
// Check if there's any pending save state actions.
SaveState::Process();
if (coreState != CORE_STEPPING) {
return;
}
host->UpdateDisassembly();
host->UpdateMemView();
// Need to check inside the lock to avoid races.
Core_WaitStepping();
// We may still be stepping without singleStepPending to process a save state.
if (singleStepPending && coreState == CORE_STEPPING) {
singleStepPending = false;
Core_SingleStep();
// Update disasm dialog.
host->UpdateDisassembly();
host->UpdateMemView();
}
}
// Many platforms, like Android, do not call this function but handle things on their own.
// Instead they simply call NativeRender and NativeUpdate directly.
void Core_Run(GraphicsContext *ctx) {
host->UpdateDisassembly();
while (true) {
reswitch:
if (GetUIState() != UISTATE_INGAME) {
CoreStateProcessed();
if (GetUIState() == UISTATE_EXIT) {
@@ -270,38 +304,9 @@ void Core_Run(GraphicsContext *ctx) {
// We should never get here on Android.
case CORE_STEPPING:
singleStepPending = false;
CoreStateProcessed();
// Check if there's any pending savestate actions.
SaveState::Process();
if (coreState == CORE_POWERDOWN) {
Core_ProcessStepping();
if (coreState == CORE_POWERDOWN)
return;
}
// wait for step command..
host->UpdateDisassembly();
host->UpdateMemView();
host->SendCoreWait(true);
{
std::unique_lock<std::mutex> guard(m_hStepMutex);
m_StepCond.wait(guard);
}
host->SendCoreWait(false);
// No step pending? Let's go back to the wait.
if (!singleStepPending || coreState != CORE_STEPPING) {
if (coreState == CORE_POWERDOWN) {
return;
}
goto reswitch;
}
Core_SingleStep();
// update disasm dialog
host->UpdateDisassembly();
host->UpdateMemView();
break;
case CORE_POWERUP:
View
@@ -34,6 +34,7 @@ void Core_SetGraphicsContext(GraphicsContext *ctx);
void Core_EnableStepping(bool step);
void Core_DoSingleStep();
void Core_UpdateSingleStep();
void Core_ProcessStepping();
// Changes every time we enter stepping.
int Core_GetSteppingCounter();
@@ -54,6 +55,7 @@ bool Core_IsStepping();
bool Core_IsActive();
bool Core_IsInactive();
// Warning: these currently work only on Windows.
void Core_WaitInactive();
void Core_WaitInactive(int milliseconds);
View
@@ -50,8 +50,6 @@ class Host {
virtual void SaveSymbolMap() {}
virtual void SetWindowTitle(const char *message) {}
virtual void SendCoreWait(bool) {}
// While debugging is active, it's perfectly fine for these to block.
virtual bool GPUDebuggingActive() { return false; }
virtual void GPUNotifyCommand(u32 pc) {}

0 comments on commit c15ade3

Please sign in to comment.