From 59465911d741ce9ee7c7481927fd5a5648d1fe50 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Fri, 2 Sep 2016 02:18:14 +0000 Subject: [PATCH] CoreTiming: Fix scheduling into the past ForceExceptionCheck messes up the downcount and slice length if the callback is scheduled into the past (g_slice_length becomes negative) --- Source/Core/Core/CoreTiming.cpp | 3 ++- Source/UnitTests/Core/CoreTimingTest.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 329f63a7ae..50747cf59a 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -282,11 +282,12 @@ void RemoveAllEvents(EventType* event_type) void ForceExceptionCheck(s64 cycles) { + cycles = std::max(0, cycles); if (DowncountToCycles(PowerPC::ppcState.downcount) > cycles) { // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here. // Account for cycles already executed by adjusting the g_slice_length - g_slice_length -= (DowncountToCycles(PowerPC::ppcState.downcount) - static_cast(cycles)); + g_slice_length -= DowncountToCycles(PowerPC::ppcState.downcount) - static_cast(cycles); PowerPC::ppcState.downcount = CyclesToDowncount(static_cast(cycles)); } } diff --git a/Source/UnitTests/Core/CoreTimingTest.cpp b/Source/UnitTests/Core/CoreTimingTest.cpp index 305232e8a3..f87e4a7b21 100644 --- a/Source/UnitTests/Core/CoreTimingTest.cpp +++ b/Source/UnitTests/Core/CoreTimingTest.cpp @@ -241,6 +241,13 @@ TEST(CoreTiming, ScheduleIntoPast) CoreTiming::g_global_timer += 1000; Core::DeclareAsCPUThread(); AdvanceAndCheck(1, MAX_SLICE_LENGTH, MAX_SLICE_LENGTH + 1000); + + // Schedule directly into the past from the CPU. + // This shouldn't happen in practice, but it's best if we don't mess up the slice length and + // downcount if we do. + CoreTiming::ScheduleEvent(-1000, s_cb_next, CB_IDS[0]); + EXPECT_EQ(0, PowerPC::ppcState.downcount); + AdvanceAndCheck(0, MAX_SLICE_LENGTH, 1000); } TEST(CoreTiming, Overclocking)