Merge pull request #774 from unknownbrackets/savestates

Wait for jit to exit the runloop in debug, quit, and savestates
This commit is contained in:
Henrik Rydgård 2013-02-23 14:27:05 -08:00
commit 2891576549
10 changed files with 61 additions and 88 deletions

View File

@ -33,13 +33,24 @@
// HANDLE m_hStepEvent;
event m_hStepEvent;
recursive_mutex m_hStepMutex;
event m_hInactiveEvent;
recursive_mutex m_hInactiveMutex;
// This can be read and written from ANYWHERE.
volatile CoreState coreState = CORE_STEPPING;
// Note: intentionally not used for CORE_NEXTFRAME.
volatile bool coreStatePending = false;
void Core_UpdateState(CoreState newState)
{
if ((coreState == CORE_RUNNING || coreState == CORE_NEXTFRAME) && newState != CORE_RUNNING)
coreStatePending = true;
coreState = newState;
}
void Core_ErrorPause()
{
coreState = CORE_ERROR;
Core_UpdateState(CORE_ERROR);
}
void Core_Pause()
@ -56,7 +67,7 @@ void Core_Halt(const char *msg)
void Core_Stop()
{
coreState = CORE_POWERDOWN;
Core_UpdateState(CORE_POWERDOWN);
m_hStepEvent.notify_one();
}
@ -65,6 +76,23 @@ bool Core_IsStepping()
return coreState == CORE_STEPPING || coreState == CORE_POWERDOWN;
}
bool Core_IsInactive()
{
return coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME && !coreStatePending;
}
void Core_WaitInactive()
{
while (!Core_IsInactive())
m_hInactiveEvent.wait(m_hInactiveMutex);
}
void Core_WaitInactive(int milliseconds)
{
while (!Core_IsInactive())
m_hInactiveEvent.wait_for(m_hInactiveMutex, milliseconds);
}
void Core_RunLoop()
{
while (!coreState) {
@ -110,6 +138,10 @@ reswitch:
// We should never get here on Android.
case CORE_STEPPING:
if (coreStatePending)
m_hInactiveEvent.notify_one();
coreStatePending = false;
//1: wait for step command..
#if defined(USING_QT_UI) || defined(_DEBUG)
host->UpdateDisassembly();
@ -142,8 +174,13 @@ reswitch:
case CORE_POWERDOWN:
case CORE_ERROR:
case CORE_NEXTFRAME:
//1: Exit loop!!
if (coreStatePending)
m_hInactiveEvent.notify_one();
coreStatePending = false;
return;
case CORE_NEXTFRAME:
return;
}
}
@ -158,7 +195,7 @@ void Core_EnableStepping(bool step)
#if defined(_DEBUG)
host->SetDebugMode(true);
#endif
coreState = CORE_STEPPING;
Core_UpdateState(CORE_STEPPING);
}
else
{
@ -166,6 +203,7 @@ void Core_EnableStepping(bool step)
host->SetDebugMode(false);
#endif
coreState = CORE_RUNNING;
coreStatePending = false;
m_hStepEvent.notify_one();
}
}

View File

@ -43,5 +43,10 @@ enum CoreState
CORE_NEXTFRAME,
};
void Core_UpdateState(CoreState newState);
bool Core_IsInactive();
void Core_WaitInactive();
void Core_WaitInactive(int milliseconds);
extern volatile CoreState coreState;

View File

@ -133,14 +133,14 @@ void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp)
void CBreakPoints::InvalidateJit(u32 _iAddress)
{
// Don't want to clear cache while running, I think?
if (MIPSComp::jit && coreState == CORE_STEPPING)
if (MIPSComp::jit && Core_IsInactive())
MIPSComp::jit->ClearCacheAt(_iAddress);
}
void CBreakPoints::InvalidateJit()
{
// Don't want to clear cache while running, I think?
if (MIPSComp::jit && coreState == CORE_STEPPING)
if (MIPSComp::jit && Core_IsInactive())
MIPSComp::jit->ClearCache();
}

View File

@ -187,7 +187,7 @@ namespace MIPSInt
void Int_Break(u32 op)
{
ERROR_LOG(CPU, "BREAK!");
coreState = CORE_STEPPING;
Core_UpdateState(CORE_STEPPING);
PC += 4;
}

View File

@ -359,7 +359,7 @@ void Jit::WriteExitDestInEAX()
// TODO: "Ignore" this so other threads can continue?
if (g_Config.bIgnoreBadMemAccess)
MOV(32, M((void*)&coreState), Imm32(CORE_ERROR));
ABI_CallFunctionA(thunks.ProtectFunction((void *) Core_UpdateState, 1), Imm32(CORE_ERROR));
JMP(asm_.dispatcherCheckCoreState, true);
}
else

View File

@ -56,6 +56,10 @@ u8 *GetPointer(const u32 address)
else
{
ERROR_LOG(MEMMAP, "Unknown GetPointer %08x PC %08x LR %08x", address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]);
if (!g_Config.bIgnoreBadMemAccess) {
Core_EnableStepping(true);
host->SetDebugMode(true);
}
return 0;
}
}

View File

@ -90,7 +90,7 @@ namespace SaveState
// Don't actually run it until next CoreTiming::Advance().
// It's possible there might be a duplicate but it won't hurt us.
if (Core_IsStepping() && __KernelIsRunning())
if (Core_IsInactive() && __KernelIsRunning())
{
// Warning: this may run on a different thread.
Process(0, 0);

View File

@ -388,26 +388,10 @@ void SaveStateActionFinished(bool result, void *userdata)
msgBox.exec();
return;
}
MainWindow* mainWindow = (MainWindow*)userdata;
if (g_State.bEmuThreadStarted && mainWindow->GetNextState() == CORE_RUNNING)
{
if(mainWindow->GetDialogDisasm())
mainWindow->GetDialogDisasm()->Go();
}
}
void MainWindow::on_action_FileLoadStateFile_triggered()
{
if (g_State.bEmuThreadStarted)
{
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
if(dialogDisasm)
{
dialogDisasm->Stop();
}
}
QFileDialog dialog(0,"Load state");
dialog.setFileMode(QFileDialog::ExistingFile);
QStringList filters;
@ -425,14 +409,6 @@ void MainWindow::on_action_FileLoadStateFile_triggered()
void MainWindow::on_action_FileSaveStateFile_triggered()
{
if (g_State.bEmuThreadStarted)
{
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
if(dialogDisasm)
{
dialogDisasm->Stop();
}
}
QFileDialog dialog(0,"Save state");
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setAcceptMode(QFileDialog::AcceptSave);
@ -449,27 +425,11 @@ void MainWindow::on_action_FileSaveStateFile_triggered()
void MainWindow::on_action_FileQuickloadState_triggered()
{
if (g_State.bEmuThreadStarted)
{
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
if(dialogDisasm)
{
dialogDisasm->Stop();
}
}
SaveState::LoadSlot(0, SaveStateActionFinished, this);
}
void MainWindow::on_action_FileQuickSaveState_triggered()
{
if (g_State.bEmuThreadStarted)
{
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
if(dialogDisasm)
{
dialogDisasm->Stop();
}
}
SaveState::SaveSlot(0, SaveStateActionFinished, this);
}

View File

@ -308,7 +308,7 @@ namespace MainWindow
if (disasmWindow[i])
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
Sleep(100);//UGLY wait for event instead
Core_WaitInactive();
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
@ -328,7 +328,7 @@ namespace MainWindow
if (disasmWindow[i])
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
Sleep(100);//UGLY wait for event instead
Core_WaitInactive();
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
@ -354,13 +354,6 @@ namespace MainWindow
break;
case ID_FILE_LOADSTATEFILE:
if (g_State.bEmuThreadStarted)
{
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
}
if (W32Util::BrowseForFileName(true, hWnd, "Load state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn))
{
SetCursor(LoadCursor(0,IDC_WAIT));
@ -369,13 +362,6 @@ namespace MainWindow
break;
case ID_FILE_SAVESTATEFILE:
if (g_State.bEmuThreadStarted)
{
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
}
if (W32Util::BrowseForFileName(false, hWnd, "Save state",0,"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0","ppst",fn))
{
SetCursor(LoadCursor(0,IDC_WAIT));
@ -386,25 +372,11 @@ namespace MainWindow
// TODO: Add UI for multiple slots
case ID_FILE_QUICKLOADSTATE:
if (g_State.bEmuThreadStarted)
{
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
}
SetCursor(LoadCursor(0,IDC_WAIT));
SaveState::LoadSlot(0, SaveStateActionFinished);
break;
case ID_FILE_QUICKSAVESTATE:
if (g_State.bEmuThreadStarted)
{
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
}
SetCursor(LoadCursor(0,IDC_WAIT));
SaveState::SaveSlot(0, SaveStateActionFinished);
break;
@ -643,7 +615,8 @@ namespace MainWindow
break;
case WM_CLOSE:
Sleep(100);//UGLY wait for event instead
Core_Stop();
Core_WaitInactive(200);
EmuThread_Stop();
/*
@ -896,13 +869,6 @@ namespace MainWindow
if (!result)
MessageBox(0, "Savestate failure. Please try again later.", "Sorry", MB_OK);
SetCursor(LoadCursor(0, IDC_ARROW));
if (g_State.bEmuThreadStarted && nextState == CORE_RUNNING)
{
for (int i=0; i<numCPUs; i++)
if (disasmWindow[i])
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_GO, 0);
}
}
void SetNextState(CoreState state)

2
native

@ -1 +1 @@
Subproject commit a9a067ef8473628f170dfdab1f7692b53a5f130b
Subproject commit 9c183fcca8416a34d510880d483ccf5f2ec573f4