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
This commit is contained in:
Timo Kreuzer 2011-08-30 12:01:01 +00:00
parent e03d0348d9
commit ee0c854ff6

View file

@ -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;
}