System: Fix lockup with runahead enabled
This commit is contained in:
parent
ef59a0da12
commit
3455a0d151
|
@ -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());
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue