Skip to content

Commit

Permalink
Core: Refactor stepping and locking.
Browse files Browse the repository at this point in the history
This should fix some race conditions with the cond vars.
  • Loading branch information
unknownbrackets committed Jun 7, 2018
1 parent 6bf6490 commit c15ade3
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 35 deletions.
71 changes: 38 additions & 33 deletions Core/Core.cpp
Expand Up @@ -87,7 +87,6 @@ void Core_NotifyLifecycle(CoreLifecycle stage) {

void Core_Stop() {
Core_UpdateState(CORE_POWERDOWN);
m_StepCond.notify_all();
}

bool Core_IsStepping() {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}

Expand 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) {
Expand All @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions Core/Core.h
Expand Up @@ -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();

Expand All @@ -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);

Expand Down
2 changes: 0 additions & 2 deletions Core/Host.h
Expand Up @@ -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) {}
Expand Down

0 comments on commit c15ade3

Please sign in to comment.