Author: tkreuzer Date: Tue Aug 30 12:01:01 2011 New Revision: 53496
URL: http://svn.reactos.org/svn/reactos?rev=53496&view=rev Log: [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.
Modified: trunk/reactos/hal/halx86/generic/timer.c
Modified: trunk/reactos/hal/halx86/generic/timer.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/timer.c?... ============================================================================== --- trunk/reactos/hal/halx86/generic/timer.c [iso-8859-1] (original) +++ trunk/reactos/hal/halx86/generic/timer.c [iso-8859-1] Tue Aug 30 12:01:01 2011 @@ -253,6 +253,7 @@ { LARGE_INTEGER CurrentPerfCounter; ULONG CounterValue, ClockDelta; + KIRQL OldIrql;
/* If caller wants performance frequency, return hardcoded value */ if (PerformanceFrequency) PerformanceFrequency->QuadPart = PIT_FREQUENCY; @@ -262,6 +263,10 @@
/* 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 { @@ -287,13 +292,21 @@ /* 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; }