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;
}
void CPU::ExitExecution()
[[noreturn]] void CPU::ExitExecution()
{
// can't exit while running events without messing things up
DebugAssert(!TimingEvents::IsRunningEvents());

View file

@ -145,7 +145,7 @@ void ExecutionModeChanged();
void Execute();
// Forces an early exit from the CPU dispatcher.
void ExitExecution();
[[noreturn]] void ExitExecution();
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 IsExecutionInterrupted();
static void ExitExecution();
static void CheckForAndExitExecution();
static void SetRewinding(bool enabled);
static bool SaveRewindState();
@ -557,15 +557,20 @@ bool System::IsRunning()
return s_state == State::Running;
}
bool System::IsExecutionInterrupted()
ALWAYS_INLINE bool System::IsExecutionInterrupted()
{
return s_state != State::Running || s_system_interrupted;
}
void System::ExitExecution()
ALWAYS_INLINE_RELEASE void System::CheckForAndExitExecution()
{
TimingEvents::CancelRunningEvent();
CPU::ExitExecution();
if (IsExecutionInterrupted()) [[unlikely]]
{
s_system_interrupted = false;
TimingEvents::CancelRunningEvent();
CPU::ExitExecution();
}
}
bool System::IsPaused()
@ -2048,13 +2053,7 @@ void System::FrameDone()
Host::PumpMessagesOnCPUThread();
InputManager::PollSources();
g_gpu->RestoreDeviceContext();
if (IsExecutionInterrupted())
{
s_system_interrupted = false;
ExitExecution();
return;
}
CheckForAndExitExecution();
}
if (DoRunahead())
@ -2159,13 +2158,7 @@ void System::FrameDone()
{
Host::PumpMessagesOnCPUThread();
InputManager::PollSources();
if (IsExecutionInterrupted())
{
s_system_interrupted = false;
ExitExecution();
return;
}
CheckForAndExitExecution();
}
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
// was never saved, so return but don't decrement the counter
InterruptExecution();
CheckForAndExitExecution();
return true;
}
else if (s_runahead_replay_frames == 0)

View file

@ -384,7 +384,7 @@ void TimingEvents::CommitLeftoverTicks()
{
#ifdef _DEBUG
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
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);
s_state.current_event = nullptr;
// Add pending ticks to the CPU, this'll happen if we saved state when we weren't paused.
const TickCount pending_ticks =
@ -489,7 +490,12 @@ bool TimingEvents::DoState(StateWrapper& sw)
}
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();
UpdateCPUDowncount();
}
else
{
@ -498,7 +504,9 @@ bool TimingEvents::DoState(StateWrapper& sw)
for (TimingEvent* event = s_state.active_events_head; event; event = event->next)
{
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_period);
sw.Do(&event->m_interval);