Core: Allow CPUManager::SetStepping to be called from the CPU thread so a call doesn't need to be routed through the host thread on boot.

This commit is contained in:
Jordan Woyak 2025-11-19 02:45:39 -06:00
parent 19f1d329c9
commit 9f0a5c2a37
4 changed files with 15 additions and 17 deletions

View File

@ -314,15 +314,12 @@ void UndeclareAsGPUThread()
}
// For the CPU Thread only.
static void CPUSetInitialExecutionState(bool force_paused = false)
static void CPUSetInitialExecutionState(Core::System& system, bool force_paused = false)
{
// The CPU starts in stepping state, and will wait until a new state is set before executing.
// SetState isn't safe to call from the CPU thread, so we ask the host thread to call it.
QueueHostJob([force_paused](Core::System& system) {
bool paused = SConfig::GetInstance().bBootToPause || force_paused;
SetState(system, paused ? State::Paused : State::Running, true, true);
Host_UpdateDisasmDialog();
});
const bool paused = SConfig::GetInstance().bBootToPause || force_paused;
SetState(system, paused ? State::Paused : State::Running, true, true);
Host_UpdateDisasmDialog();
}
// Create the CPU thread, which is a CPU + Video thread in Single Core mode.
@ -371,7 +368,7 @@ static void CpuThread(Core::System& system, const std::optional<std::string>& sa
if (!gdb_socket.empty() && !AchievementManager::GetInstance().IsHardcoreModeActive())
{
GDBStub::InitLocal(gdb_socket.data());
CPUSetInitialExecutionState(true);
CPUSetInitialExecutionState(system, true);
}
else
#endif
@ -380,11 +377,11 @@ static void CpuThread(Core::System& system, const std::optional<std::string>& sa
if (gdb_port > 0 && !AchievementManager::GetInstance().IsHardcoreModeActive())
{
GDBStub::Init(gdb_port);
CPUSetInitialExecutionState(true);
CPUSetInitialExecutionState(system, true);
}
else
{
CPUSetInitialExecutionState();
CPUSetInitialExecutionState(system);
}
}
}
@ -430,7 +427,7 @@ static void FifoPlayerThread(Core::System& system, const std::optional<std::stri
s_state.compare_exchange_strong(expected, State::Running);
}
CPUSetInitialExecutionState();
CPUSetInitialExecutionState(system);
system.GetCPU().Run();

View File

@ -143,8 +143,7 @@ bool IsGPUThread();
bool WantsDeterminism();
// SetState can't be called by the CPU thread, but can be called by any thread that isn't launched
// by the emulator core.
// SetState can be called from any thread.
void SetState(Core::System& system, State state, bool report_state_change = true,
bool override_achievement_restrictions = false);
State GetState(Core::System& system);

View File

@ -308,16 +308,18 @@ void CPUManager::SetStepping(bool stepping)
{
SetStateLocked(State::Stepping);
while (m_state_cpu_thread_active)
if (!Core::IsCPUThread())
{
m_state_cpu_idle_cvar.wait(state_lock);
while (m_state_cpu_thread_active)
m_state_cpu_idle_cvar.wait(state_lock);
}
RunAdjacentSystems(false);
}
else if (SetStateLocked(State::Running))
{
m_state_cpu_cvar.notify_one();
if (!Core::IsCPUThread())
m_state_cpu_cvar.notify_one();
m_time_played_finish_sync.Set();
RunAdjacentSystems(true);
}

View File

@ -63,7 +63,7 @@ public:
// StepOpcode (Steps one Opcode)
void StepOpcode(Common::Event* event = nullptr);
// Enable or Disable Stepping. [Will deadlock if called from a system thread]
// Enable or Disable Stepping.
void SetStepping(bool stepping);
// Breakpoint activation for system threads. Similar to SetStepping(true).