diff --git a/src/common/Timer.cpp b/src/common/Timer.cpp index 1551ca751..a4fe0f76f 100644 --- a/src/common/Timer.cpp +++ b/src/common/Timer.cpp @@ -102,7 +102,7 @@ static uint64_t pit_next(uint64_t now) uint64_t next = pit_last + pit_period; if (now >= next) { - xbox::KiClockIsr((now - pit_last - pit_period) / 1000); + xbox::KiClockIsr(now - pit_last); pit_last = get_now(); return pit_period; } @@ -151,7 +151,7 @@ static uint64_t get_next(uint64_t now) xbox::void_xt NTAPI system_events(xbox::PVOID arg) { // Testing shows that, if this thread has the same priority of the other xbox threads, it can take tens, even hundreds of ms to complete a single loop. - // So we increase its priority to above normal, so that it completes a loop roughly every 3.1ms + // So we increase its priority to above normal, so that it scheduled more often SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); while (true) { diff --git a/src/core/kernel/exports/EmuKrnlKi.cpp b/src/core/kernel/exports/EmuKrnlKi.cpp index 958540554..682fbcb46 100644 --- a/src/core/kernel/exports/EmuKrnlKi.cpp +++ b/src/core/kernel/exports/EmuKrnlKi.cpp @@ -146,19 +146,25 @@ xbox::void_xt xbox::KiWaitListUnlock() KiWaitListMtx.Mtx.unlock(); } -xbox::void_xt xbox::KiClockIsr(ulonglong_xt ExtraMs) +xbox::void_xt xbox::KiClockIsr(ulonglong_xt TotalUs) { KIRQL OldIrql; LARGE_INTEGER InterruptTime, SystemTime; ULONG Hand; DWORD OldKeTickCount; + static uint64_t LostUs; + uint64_t TotalMs = TotalUs / 1000; + LostUs += (TotalUs - TotalMs * 1000); + uint64_t RecoveredMs = LostUs / 1000; + TotalMs += RecoveredMs; + LostUs -= (RecoveredMs * 1000); OldIrql = KfRaiseIrql(CLOCK_LEVEL); // Update the interrupt time InterruptTime.u.LowPart = KeInterruptTime.LowPart; InterruptTime.u.HighPart = KeInterruptTime.High1Time; - InterruptTime.QuadPart += (CLOCK_TIME_INCREMENT * (1 + ExtraMs)); + InterruptTime.QuadPart += (CLOCK_TIME_INCREMENT * TotalMs); KeInterruptTime.High2Time = InterruptTime.u.HighPart; KeInterruptTime.LowPart = InterruptTime.u.LowPart; KeInterruptTime.High1Time = InterruptTime.u.HighPart; @@ -178,7 +184,7 @@ xbox::void_xt xbox::KiClockIsr(ulonglong_xt ExtraMs) else { SystemTime.u.LowPart = KeSystemTime.LowPart; SystemTime.u.HighPart = KeSystemTime.High1Time; - SystemTime.QuadPart += (CLOCK_TIME_INCREMENT * (1 + ExtraMs)); + SystemTime.QuadPart += (CLOCK_TIME_INCREMENT * TotalMs); KeSystemTime.High2Time = SystemTime.u.HighPart; KeSystemTime.LowPart = SystemTime.u.LowPart; KeSystemTime.High1Time = SystemTime.u.HighPart; @@ -186,7 +192,7 @@ xbox::void_xt xbox::KiClockIsr(ulonglong_xt ExtraMs) // Update the tick counter OldKeTickCount = KeTickCount; - KeTickCount += (1 + static_cast(ExtraMs)); + KeTickCount += (1 + static_cast(TotalMs)); // Because this function must be fast to continuously update the kernel clocks, if somebody else is currently // holding the lock, we won't wait and instead skip the check of the timers for this cycle diff --git a/src/core/kernel/exports/EmuKrnlKi.h b/src/core/kernel/exports/EmuKrnlKi.h index 868b64c1c..d436093a1 100644 --- a/src/core/kernel/exports/EmuKrnlKi.h +++ b/src/core/kernel/exports/EmuKrnlKi.h @@ -66,7 +66,7 @@ namespace xbox void_xt KiWaitListUnlock(); - void_xt KiClockIsr(ulonglong_xt ExtraMs); + void_xt KiClockIsr(ulonglong_xt TotalUs); xbox::void_xt NTAPI KiCheckTimerTable (