System: Fix lockup with runahead enabled

This commit is contained in:
Stenzek 2024-08-20 11:50:52 +10:00
parent 18ca0da78d
commit 3e8f2f6b1c
No known key found for this signature in database
4 changed files with 26 additions and 23 deletions

View file

@ -2016,7 +2016,7 @@ bool CPU::UpdateDebugDispatcherFlag()
return true; return true;
} }
void CPU::ExitExecution() [[noreturn]] void CPU::ExitExecution()
{ {
// can't exit while running events without messing things up // can't exit while running events without messing things up
DebugAssert(!TimingEvents::IsRunningEvents()); DebugAssert(!TimingEvents::IsRunningEvents());

View file

@ -145,7 +145,7 @@ void ExecutionModeChanged();
void Execute(); void Execute();
// Forces an early exit from the CPU dispatcher. // Forces an early exit from the CPU dispatcher.
void ExitExecution(); [[noreturn]] void ExitExecution();
ALWAYS_INLINE static Registers& GetRegs() ALWAYS_INLINE static Registers& GetRegs()
{ {

View file

@ -204,7 +204,7 @@ static u32 CompressAndWriteStateData(std::FILE* fp, std::span<const u8> src, Sav
static bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display, bool is_memory_state); static bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display, bool is_memory_state);
static bool IsExecutionInterrupted(); static bool IsExecutionInterrupted();
static void ExitExecution(); static void CheckForAndExitExecution();
static void SetRewinding(bool enabled); static void SetRewinding(bool enabled);
static bool SaveRewindState(); static bool SaveRewindState();
@ -557,15 +557,20 @@ bool System::IsRunning()
return s_state == State::Running; return s_state == State::Running;
} }
bool System::IsExecutionInterrupted() ALWAYS_INLINE bool System::IsExecutionInterrupted()
{ {
return s_state != State::Running || s_system_interrupted; return s_state != State::Running || s_system_interrupted;
} }
void System::ExitExecution() ALWAYS_INLINE_RELEASE void System::CheckForAndExitExecution()
{ {
TimingEvents::CancelRunningEvent(); if (IsExecutionInterrupted()) [[unlikely]]
CPU::ExitExecution(); {
s_system_interrupted = false;
TimingEvents::CancelRunningEvent();
CPU::ExitExecution();
}
} }
bool System::IsPaused() bool System::IsPaused()
@ -2048,13 +2053,7 @@ void System::FrameDone()
Host::PumpMessagesOnCPUThread(); Host::PumpMessagesOnCPUThread();
InputManager::PollSources(); InputManager::PollSources();
g_gpu->RestoreDeviceContext(); g_gpu->RestoreDeviceContext();
CheckForAndExitExecution();
if (IsExecutionInterrupted())
{
s_system_interrupted = false;
ExitExecution();
return;
}
} }
if (DoRunahead()) if (DoRunahead())
@ -2159,13 +2158,7 @@ void System::FrameDone()
{ {
Host::PumpMessagesOnCPUThread(); Host::PumpMessagesOnCPUThread();
InputManager::PollSources(); InputManager::PollSources();
CheckForAndExitExecution();
if (IsExecutionInterrupted())
{
s_system_interrupted = false;
ExitExecution();
return;
}
} }
g_gpu->RestoreDeviceContext(); g_gpu->RestoreDeviceContext();
@ -4831,6 +4824,8 @@ bool System::DoRunahead()
// we don't want to save the frame we just loaded. but we are "one frame ahead", because the frame we just tossed // we don't want to save the frame we just loaded. but we are "one frame ahead", because the frame we just tossed
// was never saved, so return but don't decrement the counter // was never saved, so return but don't decrement the counter
InterruptExecution();
CheckForAndExitExecution();
return true; return true;
} }
else if (s_runahead_replay_frames == 0) else if (s_runahead_replay_frames == 0)

View file

@ -384,7 +384,7 @@ void TimingEvents::CommitLeftoverTicks()
{ {
#ifdef _DEBUG #ifdef _DEBUG
if (s_state.event_run_tick_counter > s_state.global_tick_counter) if (s_state.event_run_tick_counter > s_state.global_tick_counter)
WARNING_LOG("Late-running {} ticks before execution", s_state.event_run_tick_counter - s_state.global_tick_counter); DEV_LOG("Late-running {} ticks before execution", s_state.event_run_tick_counter - s_state.global_tick_counter);
#endif #endif
CommitGlobalTicks(s_state.event_run_tick_counter); CommitGlobalTicks(s_state.event_run_tick_counter);
@ -441,6 +441,7 @@ bool TimingEvents::DoState(StateWrapper& sw)
} }
DEBUG_LOG("Loaded {} events from save state.", event_count); DEBUG_LOG("Loaded {} events from save state.", event_count);
s_state.current_event = nullptr;
// Add pending ticks to the CPU, this'll happen if we saved state when we weren't paused. // Add pending ticks to the CPU, this'll happen if we saved state when we weren't paused.
const TickCount pending_ticks = const TickCount pending_ticks =
@ -489,7 +490,12 @@ bool TimingEvents::DoState(StateWrapper& sw)
} }
DEBUG_LOG("Loaded {} events from save state.", event_count); DEBUG_LOG("Loaded {} events from save state.", event_count);
// Even if we're actually running an event, we don't want to set it to a new counter.
s_state.current_event = nullptr;
SortEvents(); SortEvents();
UpdateCPUDowncount();
} }
else else
{ {
@ -498,7 +504,9 @@ bool TimingEvents::DoState(StateWrapper& sw)
for (TimingEvent* event = s_state.active_events_head; event; event = event->next) for (TimingEvent* event = s_state.active_events_head; event; event = event->next)
{ {
sw.Do(&event->m_name); sw.Do(&event->m_name);
sw.Do(&event->m_next_run_time); GlobalTicks next_run_time =
(s_state.current_event == event) ? s_state.current_event_next_run_time : event->m_next_run_time;
sw.Do(&next_run_time);
sw.Do(&event->m_last_run_time); sw.Do(&event->m_last_run_time);
sw.Do(&event->m_period); sw.Do(&event->m_period);
sw.Do(&event->m_interval); sw.Do(&event->m_interval);