Core: Threadsafety Synchronization Fixes (Frame Advance / FifoPlayer)
Fix Frame Advance and FifoPlayer pause/unpause/stop. CPU::EnableStepping is not atomic but is called from multiple threads which races and leaves the system in a random state; also instruction stepping was unstable, m_StepEvent had an almost random value because of the dual purpose it served which could cause races where CPU::Run would SingleStep when it was supposed to be sleeping. FifoPlayer never FinishStateMove()d which was causing it to deadlock. Rather than partially reimplementing CPU::Run, just use CPUCoreBase and then call CPU::Run(). More DRY and less likely to have weird bugs specific to the player (i.e the previous freezing on pause/stop). Refactor PowerPC::state into CPU since it manages the state of the CPU Thread which is controlled by CPU, not PowerPC. This simplifies the architecture somewhat and eliminates races that can be caused by calling PowerPC state functions directly instead of using CPU's (because they bypassed the EnableStepping lock).
This commit is contained in:
1 parent
0283ce2a7c
commit
c1922783f8
27 files changed
+590
-319
No files matched your search
@@ -11,14 +11,12 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "Core/Debugger/PPCDebugInterface.h"
|
||||
#include "Core/PowerPC/CPUCoreBase.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/PPCCache.h"
|
||||
|
||||
class CPUCoreBase;
|
||||
class PointerWrap;
|
||||
|
||||
extern CPUCoreBase *cpu_core_base;
|
||||
|
||||
namespace PowerPC
|
||||
{
|
||||
|
||||
@@ -129,13 +127,6 @@ struct PowerPCState
|
||||
static_assert(offsetof(PowerPC::PowerPCState, above_fits_in_first_0x100) <= 0x100, "top of PowerPCState too big");
|
||||
#endif
|
||||
|
||||
enum CPUState
|
||||
{
|
||||
CPU_RUNNING = 0,
|
||||
CPU_STEPPING = 2,
|
||||
CPU_POWERDOWN = 3,
|
||||
};
|
||||
|
||||
extern PowerPCState ppcState;
|
||||
|
||||
extern Watches watches;
|
||||
@@ -148,19 +139,26 @@ void Shutdown();
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
CoreMode GetMode();
|
||||
// [NOT THREADSAFE] CPU Thread or CPU::PauseAndLock or CORE_UNINITIALIZED
|
||||
void SetMode(CoreMode _coreType);
|
||||
const char* GetCPUName();
|
||||
|
||||
// Set the current CPU Core to the given implementation until removed.
|
||||
// Remove the current injected CPU Core by passing nullptr.
|
||||
// While an external CPUCoreBase is injected, GetMode() will return MODE_INTERPRETER.
|
||||
// Init() will be called when added and Shutdown() when removed.
|
||||
// [Threadsafety: Same as SetMode(), except it cannot be called from inside the CPU
|
||||
// run loop on the CPU Thread - it doesn't make sense for a CPU to remove itself
|
||||
// while it is CPU_RUNNING]
|
||||
void InjectExternalCPUCore(CPUCoreBase* core);
|
||||
|
||||
// Stepping requires the CPU Execution lock (CPU::PauseAndLock or CPU Thread)
|
||||
// It's not threadsafe otherwise.
|
||||
void SingleStep();
|
||||
void CheckExceptions();
|
||||
void CheckExternalExceptions();
|
||||
void CheckBreakPoints();
|
||||
void RunLoop();
|
||||
void Start();
|
||||
void Pause();
|
||||
void Stop();
|
||||
void FinishStateMove();
|
||||
CPUState GetState();
|
||||
const volatile CPUState *GetStatePtr(); // this oddity is here instead of an extern declaration to easily be able to find all direct accesses throughout the code.
|
||||
|
||||
u32 CompactCR();
|
||||
void ExpandCR(u32 cr);
|
||||
|
||||
Reference in new issue
Block a user