Delegate systems teardown to EE Core when pausing

Fixes issues caused by Cleanup/Init on the Main Thread
instead of the EE Core thread. Now systems are only set up
and torn down on one thread.
This commit is contained in:
Silent 2021-09-21 20:07:34 +02:00 committed by Kojin
parent e6e7a55d7e
commit 4c941f81ec
12 changed files with 85 additions and 73 deletions

View File

@ -182,7 +182,7 @@ void DebugInterface::pauseCpu()
{
SysCoreThread& core = GetCoreThread();
if (!core.IsPaused())
core.Pause(true);
core.Pause({}, true);
}
void DebugInterface::resumeCpu()

View File

@ -385,8 +385,8 @@ protected:
void OnResumeReady();
void OnSuspendInThread();
void OnPauseInThread() {}
void OnResumeInThread( bool IsSuspended );
void OnPauseInThread(SystemsMask systemsToTearDown) override {}
void OnResumeInThread(SystemsMask systemsToReinstate) override;
void OnCleanupInThread();
void GenericStall( uint size );

View File

@ -603,12 +603,12 @@ void SysMtgsThread::OnSuspendInThread()
_parent::OnSuspendInThread();
}
void SysMtgsThread::OnResumeInThread(bool isSuspended)
void SysMtgsThread::OnResumeInThread(SystemsMask systemsToReinstate)
{
if (isSuspended)
if (systemsToReinstate & System_GS)
OpenGS();
_parent::OnResumeInThread(isSuspended);
_parent::OnResumeInThread(systemsToReinstate);
}
void SysMtgsThread::OnCleanupInThread()

View File

@ -962,13 +962,9 @@ ExtraWndProcResult StatusWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
void PADconfigure()
{
HWND tmp = hWnd;
PADclose();
ScopedCoreThreadPause paused_core;
ScopedCoreThreadPause paused_core(SystemsMask::System_PAD);
Configure();
paused_core.AllowResume();
if(tmp != nullptr)
PADopen(tmp);
}
s32 PADopen(void* pDsp)

View File

@ -40,25 +40,9 @@ u32 lClocks = 0;
void SPU2configure()
{
ScopedCoreThreadPause paused_core;
SndBuffer::Cleanup();
ScopedCoreThreadPause paused_core(SystemsMask::System_SPU2);
configure();
if (IsOpened)
{
try
{
Console.Warning("SPU2: Sound output module reset");
SndBuffer::Init();
}
catch (std::exception& ex)
{
fprintf(stderr, "SPU2 Error: Could not initialize device, or something.\nReason: %s", ex.what());
SPU2close();
}
}
paused_core.AllowResume();
}

View File

@ -101,6 +101,12 @@ void SysCoreThread::OnStart()
_parent::OnStart();
}
void SysCoreThread::OnSuspendInThread()
{
TearDownSystems(static_cast<SystemsMask>(-1)); // All systems
GetMTGS().Suspend();
}
void SysCoreThread::Start()
{
GSinit();
@ -302,30 +308,26 @@ void SysCoreThread::ExecuteTaskInThread()
PCSX2_PAGEFAULT_EXCEPT;
}
void SysCoreThread::OnSuspendInThread()
void SysCoreThread::TearDownSystems(SystemsMask systemsToTearDown)
{
DEV9close();
USBclose();
DoCDVDclose();
FWclose();
PADclose();
SPU2close();
FileMcd_EmuClose();
GetMTGS().Suspend();
if (systemsToTearDown & System_DEV9) DEV9close();
if (systemsToTearDown & System_USB) USBclose();
if (systemsToTearDown & System_CDVD) DoCDVDclose();
if (systemsToTearDown & System_FW) FWclose();
if (systemsToTearDown & System_PAD) PADclose();
if (systemsToTearDown & System_SPU2) SPU2close();
if (systemsToTearDown & System_MCD) FileMcd_EmuClose();
}
void SysCoreThread::OnResumeInThread(bool isSuspended)
void SysCoreThread::OnResumeInThread(SystemsMask systemsToReinstate)
{
GetMTGS().WaitForOpen();
if (isSuspended)
{
DEV9open((void*)pDsp);
USBopen((void*)pDsp);
}
FWopen();
SPU2open((void*)pDsp);
PADopen((void*)pDsp);
FileMcd_EmuOpen();
if (systemsToReinstate & System_DEV9) DEV9open((void*)pDsp);
if (systemsToReinstate & System_USB) USBopen((void*)pDsp);
if (systemsToReinstate & System_FW) FWopen();
if (systemsToReinstate & System_SPU2) SPU2open((void*)pDsp);
if (systemsToReinstate & System_PAD) PADopen((void*)pDsp);
if (systemsToReinstate & System_MCD) FileMcd_EmuOpen();
}

View File

@ -129,7 +129,7 @@ void SysThreadBase::Suspend(bool isBlocking)
// The previous suspension state; true if the thread was running or false if it was
// closed, not running, or paused.
//
void SysThreadBase::Pause(bool debug)
void SysThreadBase::Pause(SystemsMask systemsToTearDown, bool debug)
{
if (IsSelf() || !IsRunning())
return;
@ -146,6 +146,7 @@ void SysThreadBase::Pause(bool debug)
if ((m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused))
return;
m_SystemsToTearDown.store(systemsToTearDown, std::memory_order_relaxed);
if (m_ExecMode == ExecMode_Opened)
m_ExecMode = ExecMode_Pausing;
@ -281,7 +282,7 @@ void SysThreadBase::OnCleanupInThread()
}
void SysThreadBase::OnSuspendInThread() {}
void SysThreadBase::OnResumeInThread(bool isSuspended) {}
void SysThreadBase::OnResumeInThread(SystemsMask systemsToReinstate) {}
// Tests for Pause and Suspend/Close requests. If the thread is trying to be paused or
// closed, it will enter a wait/holding pattern here in this method until the managing
@ -294,6 +295,8 @@ void SysThreadBase::OnResumeInThread(bool isSuspended) {}
// continued execution unimpeded.
bool SysThreadBase::StateCheckInThread()
{
SystemsMask systemsToTearDown {}; // Used for Pausing/Paused
switch (m_ExecMode.load())
{
@ -314,7 +317,9 @@ bool SysThreadBase::StateCheckInThread()
// -------------------------------------
case ExecMode_Pausing:
{
OnPauseInThread();
systemsToTearDown = m_SystemsToTearDown.exchange({}, std::memory_order_relaxed);
OnPauseInThread(systemsToTearDown);
m_ExecMode = ExecMode_Paused;
m_RunningLock.Release();
}
@ -328,8 +333,12 @@ bool SysThreadBase::StateCheckInThread()
if (m_ExecMode != ExecMode_Closing)
{
if (g_CDVDReset)
//AppCoreThread deals with Reseting CDVD
OnResumeInThread(false);
// AppCoreThread deals with Reseting CDVD
// Reinit all but GS, USB, DEV9, CDVD (just like with isSuspend = false previously)
OnResumeInThread(static_cast<SystemsMask>(~(System_GS|System_USB|System_DEV9|System_CDVD)));
else
// Reinit previously torn down systems
OnResumeInThread(systemsToTearDown);
g_CDVDReset = false;
break;
@ -353,7 +362,7 @@ bool SysThreadBase::StateCheckInThread()
m_sem_Resume.WaitWithoutYield();
m_RunningLock.Acquire();
OnResumeInThread(true);
OnResumeInThread(static_cast<SystemsMask>(-1)); // All systems
g_CDVDReset = false;
break;

View File

@ -26,6 +26,18 @@ using namespace Threading;
typedef SafeArray<u8> VmStateBuffer;
enum SystemsMask : uint8_t
{
System_GS = 1 << 0,
System_SPU2 = 1 << 1,
System_PAD = 1 << 2,
System_FW = 1 << 3,
System_CDVD = 1 << 4,
System_USB = 1 << 5,
System_DEV9 = 1 << 6,
System_MCD = 1 << 7,
};
// --------------------------------------------------------------------------------------
// SysThreadBase
// --------------------------------------------------------------------------------------
@ -65,6 +77,7 @@ public:
protected:
std::atomic<ExecutionMode> m_ExecMode;
std::atomic<SystemsMask> m_SystemsToTearDown {};
// This lock is used to avoid simultaneous requests to Suspend/Resume/Pause from
// contending threads.
@ -113,7 +126,7 @@ public:
virtual void Suspend(bool isBlocking = true);
virtual void Resume();
virtual void Pause(bool debug = false);
virtual void Pause(SystemsMask systemsToTearDown, bool debug = false);
virtual void PauseSelf();
virtual void PauseSelfDebug();
@ -146,15 +159,16 @@ protected:
// prior to pausing the thread (ie, when Pause() has been called on a separate thread,
// requesting this thread pause itself temporarily). After this is called, the thread
// enters a waiting state on the m_sem_Resume semaphore.
virtual void OnPauseInThread() = 0;
// Parameter:
// systemsToTearDown - a bitmask of systems to call Close functions on.
virtual void OnPauseInThread(SystemsMask systemsToTearDown) = 0;
// Extending classes should implement this, but should not call it. The parent class
// handles invocation by the following guidelines: Called from StateCheckInThread() after the
// thread has been suspended and then subsequently resumed.
// Parameter:
// isSuspended - set to TRUE if the thread is returning from a suspended state, or
// FALSE if it's returning from a paused state.
virtual void OnResumeInThread(bool isSuspended) = 0;
// systemsToTearDown - a bitmask of systems to call Open functions on.
virtual void OnResumeInThread(SystemsMask systemsToReinstate) = 0;
};
@ -220,15 +234,18 @@ protected:
virtual void Start();
virtual void OnStart();
virtual void OnSuspendInThread();
virtual void OnPauseInThread() {}
virtual void OnResumeInThread(bool IsSuspended);
virtual void OnSuspendInThread() override;
virtual void OnPauseInThread(SystemsMask systemsToTearDown) override { TearDownSystems(systemsToTearDown); }
virtual void OnResumeInThread(SystemsMask systemsToReinstate) override;
virtual void OnCleanupInThread();
virtual void ExecuteTaskInThread();
virtual void DoCpuReset();
virtual void DoCpuExecute();
void _StateCheckThrows();
private:
void TearDownSystems(SystemsMask systemsToTearDown);
};

View File

@ -577,7 +577,7 @@ void AppCoreThread::DoCpuReset()
_parent::DoCpuReset();
}
void AppCoreThread::OnResumeInThread(bool isSuspended)
void AppCoreThread::OnResumeInThread(SystemsMask systemsToReinstate)
{
if (m_resetCdvd)
{
@ -586,10 +586,10 @@ void AppCoreThread::OnResumeInThread(bool isSuspended)
DoCDVDopen();
m_resetCdvd = false;
}
else if (isSuspended)
else if (systemsToReinstate & System_CDVD)
DoCDVDopen();
_parent::OnResumeInThread(isSuspended);
_parent::OnResumeInThread(systemsToReinstate);
PostCoreStatus(CoreThread_Resumed);
}
@ -720,7 +720,7 @@ void SysExecEvent_CoreThreadClose::InvokeEvent()
void SysExecEvent_CoreThreadPause::InvokeEvent()
{
ScopedCoreThreadPause paused_core;
ScopedCoreThreadPause paused_core(m_systemsToTearDown);
_post_and_wait(paused_core);
paused_core.AllowResume();
}
@ -820,7 +820,7 @@ ScopedCoreThreadClose::~ScopedCoreThreadClose()
DESTRUCTOR_CATCHALL
}
ScopedCoreThreadPause::ScopedCoreThreadPause()
ScopedCoreThreadPause::ScopedCoreThreadPause(SystemsMask systemsToTearDown)
{
if (ScopedCore_IsFullyClosed || ScopedCore_IsPaused)
{
@ -829,11 +829,11 @@ ScopedCoreThreadPause::ScopedCoreThreadPause()
return;
}
if (!PostToSysExec(std::make_unique<SysExecEvent_CoreThreadPause>()))
if (!PostToSysExec(std::make_unique<SysExecEvent_CoreThreadPause>(systemsToTearDown)))
{
m_alreadyStopped = CoreThread.IsPaused();
if (!m_alreadyStopped)
CoreThread.Pause();
CoreThread.Pause(systemsToTearDown);
}
ScopedCore_IsPaused = true;

View File

@ -119,13 +119,17 @@ public:
virtual ~SysExecEvent_CoreThreadPause() = default;
SysExecEvent_CoreThreadPause* Clone() const { return new SysExecEvent_CoreThreadPause(*this); }
SysExecEvent_CoreThreadPause(SynchronousActionState* sync = NULL, SynchronousActionState* resume_sync = NULL, Threading::Mutex* mtx_resume = NULL)
SysExecEvent_CoreThreadPause(SystemsMask systemsToTearDown, SynchronousActionState* sync = NULL, SynchronousActionState* resume_sync = NULL, Threading::Mutex* mtx_resume = NULL)
: BaseSysExecEvent_ScopedCore(sync, resume_sync, mtx_resume)
, m_systemsToTearDown(systemsToTearDown)
{
}
protected:
void InvokeEvent();
private:
SystemsMask m_systemsToTearDown;
};
// --------------------------------------------------------------------------------------
@ -160,7 +164,7 @@ protected:
virtual void OnResumeReady();
virtual void OnPause();
virtual void OnPauseDebug();
virtual void OnResumeInThread(bool IsSuspended);
virtual void OnResumeInThread(SystemsMask systemsToReinstate) override;
virtual void OnSuspendInThread();
virtual void OnCleanupInThread();
virtual void VsyncInThread();
@ -242,7 +246,7 @@ struct ScopedCoreThreadPause : public BaseScopedCoreThread
typedef BaseScopedCoreThread _parent;
public:
ScopedCoreThreadPause();
ScopedCoreThreadPause(SystemsMask systemsToTearDown = {});
virtual ~ScopedCoreThreadPause();
};

View File

@ -1016,7 +1016,7 @@ void MainEmuFrame::Menu_Capture_Screenshot_Screenshot_As_Click(wxCommandEvent& e
// Ensure emulation is paused so that the correct image is captured
bool wasPaused = CoreThread.IsPaused();
if (!wasPaused)
CoreThread.Pause();
CoreThread.Pause({});
wxFileDialog fileDialog(this, _("Select a file"), g_Conf->Folders.Snapshots.ToAscii(), wxEmptyString, "PNG files (*.png)|*.png", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);

View File

@ -681,7 +681,7 @@ protected:
PatchesVerboseReset();
GetCoreThread().Pause();
GetCoreThread().Pause({});
SysClearExecutionCache();
for (uint i = 0; i < ArraySize(SavestateEntries); ++i)