From ee0c854ff6f68de1718dab8d5d125f3a298f81a3 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Tue, 30 Aug 2011 12:01:01 +0000 Subject: [PATCH] [HAL] We cannot make any assumptions about the latency whith which the timer interrupt fires after a rollover, since VBox (other VMs probably as well) doesn't always meet this. Add another check to KeQueryPerformanceCounter that gracefully handles missing interrupts. Also raise to DISPATCH_LEVEL, since the function is not reentrant. svn path=/trunk/; revision=53496 --- reactos/hal/halx86/generic/timer.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/reactos/hal/halx86/generic/timer.c b/reactos/hal/halx86/generic/timer.c index 917c5d1be96..b9a754166bb 100644 --- a/reactos/hal/halx86/generic/timer.c +++ b/reactos/hal/halx86/generic/timer.c @@ -253,6 +253,7 @@ KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFrequency) { LARGE_INTEGER CurrentPerfCounter; ULONG CounterValue, ClockDelta; + KIRQL OldIrql; /* If caller wants performance frequency, return hardcoded value */ if (PerformanceFrequency) PerformanceFrequency->QuadPart = PIT_FREQUENCY; @@ -263,6 +264,10 @@ KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFrequency) /* Check if interrupts are disabled */ if(!(__readeflags() & EFLAGS_INTERRUPT_MASK)) return HalpPerfCounter; + /* Raise irql to DISPATCH_LEVEL */ + OldIrql = KeGetCurrentIrql(); + if (OldIrql < DISPATCH_LEVEL) KfRaiseIrql(DISPATCH_LEVEL); + do { /* Get the current performance counter value */ @@ -287,13 +292,21 @@ KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFrequency) /* Add the clock delta */ CurrentPerfCounter.QuadPart += ClockDelta; - /* This must be true unless HalpPerfCounter has changed sign, - which takes approximately 245,118 years */ - ASSERT(CurrentPerfCounter.QuadPart >= HalpLastPerfCounter.QuadPart); + /* Check if the value is smaller then before, this means, we somehow + missed an interrupt. This is a sign that the timer interrupt + is very inaccurate. Probably a virtual machine. */ + if (CurrentPerfCounter.QuadPart < HalpLastPerfCounter.QuadPart) + { + /* We missed an interrupt. Assume we will receive it later */ + CurrentPerfCounter.QuadPart += HalpCurrentRollOver; + } /* Update the last counter value */ HalpLastPerfCounter = CurrentPerfCounter; + /* Restore previous irql */ + if (OldIrql < DISPATCH_LEVEL) KfLowerIrql(OldIrql); + /* Return the result */ return CurrentPerfCounter; }