Index: trunk/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp	(revision 53456)
+++ trunk/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp	(revision 53457)
@@ -40,4 +40,7 @@
 #include "internal-r0drv-nt.h"
 #include "internal/magics.h"
+
+/** This seems to provide better accuracy. */
+#define RTR0TIMER_NT_MANUAL_RE_ARM 1
 
 
@@ -71,4 +74,6 @@
      * is destroyed to indicate clearly that thread should exit. */
     uint32_t volatile       u32Magic;
+    /** Suspend count down for single shot omnit timers. */
+    int32_t volatile        cOmniSuspendCountDown;
     /** Flag indicating the timer is suspended. */
     bool volatile           fSuspended;
@@ -86,4 +91,8 @@
     /** The timer interval. 0 if one-shot. */
     uint64_t                u64NanoInterval;
+#ifdef RTR0TIMER_NT_MANUAL_RE_ARM
+    /** The NT start time . */
+    uint64_t                uNtStartTime;
+#endif
     /** The Nt timer object. */
     KTIMER                  NtTimer;
@@ -98,4 +107,59 @@
 
 
+#ifdef RTR0TIMER_NT_MANUAL_RE_ARM
+/**
+ * Get current NT interrupt time.
+ * @return NT interrupt time
+ */
+static uint64_t rtTimerNtQueryInterruptTime(void)
+{
+# ifdef RT_ARCH_AMD64
+    return KeQueryInterruptTime(); /* macro */
+# else
+    if (g_pfnrtKeQueryInterruptTime)
+        return g_pfnrtKeQueryInterruptTime();
+
+    /* NT4 */
+    ULARGE_INTEGER InterruptTime;
+    do
+    {
+        InterruptTime.HighPart = ((KUSER_SHARED_DATA volatile *)SharedUserData)->InterruptTime.High1Time;
+        InterruptTime.LowPart  = ((KUSER_SHARED_DATA volatile *)SharedUserData)->InterruptTime.LowPart;
+    } while (((KUSER_SHARED_DATA volatile *)SharedUserData)->InterruptTime.High2Time != InterruptTime.HighPart);
+    return InterruptTime.QuadPart;
+# endif
+}
+#endif /* RTR0TIMER_NT_MANUAL_RE_ARM */
+
+
+/**
+ * Manually re-arms an internval timer.
+ *
+ * Turns out NT doesn't necessarily do a very good job at re-arming timers
+ * accurately.
+ *
+ * @param   pTimer              The timer.
+ * @param   iTick               The current timer tick.
+ * @param   pMasterDpc          The master DPC.
+ */
+DECLINLINE(void) rtTimerNtRearmInternval(PRTTIMER pTimer, uint64_t iTick, PKDPC pMasterDpc)
+{
+#ifdef RTR0TIMER_NT_MANUAL_RE_ARM
+    Assert(pTimer->u64NanoInterval);
+
+    uint64_t uNtNext = (iTick * pTimer->u64NanoInterval) / 100 - 10; /* 1us fudge */
+    LARGE_INTEGER DueTime;
+    DueTime.QuadPart = rtTimerNtQueryInterruptTime() - pTimer->uNtStartTime;
+    if (DueTime.QuadPart < 0)
+        DueTime.QuadPart = 0;
+    if ((uint64_t)DueTime.QuadPart < uNtNext)
+        DueTime.QuadPart -= uNtNext;
+    else
+        DueTime.QuadPart = -2500; /* 0.25ms */
+
+    KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, &pTimer->aSubTimers[0].NtDpc);
+#endif
+}
+
 
 /**
@@ -125,5 +189,8 @@
         if (!pTimer->u64NanoInterval)
             ASMAtomicWriteBool(&pTimer->fSuspended, true);
-        pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->aSubTimers[0].iTick);
+        uint64_t iTick = ++pTimer->aSubTimers[0].iTick;
+        if (pTimer->u64NanoInterval)
+            rtTimerNtRearmInternval(pTimer, iTick, &pTimer->aSubTimers[0].NtDpc);
+        pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
     }
 
@@ -161,5 +228,7 @@
     {
         if (!pTimer->u64NanoInterval)
-            ASMAtomicWriteBool(&pTimer->fSuspended, true);
+            if (ASMAtomicDecS32(&pTimer->cOmniSuspendCountDown) <= 0)
+                ASMAtomicWriteBool(&pTimer->fSuspended, true);
+
         pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
     }
@@ -203,12 +272,41 @@
         RTCPUSET    OnlineSet;
         RTMpGetOnlineSet(&OnlineSet);
-        for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
-            if (    RTCpuSetIsMemberByIndex(&OnlineSet, iCpu)
-                &&  iCpuSelf != iCpu)
-                KeInsertQueueDpc(&pTimer->aSubTimers[iCpu].NtDpc, 0, 0);
-
-        if (!pTimer->u64NanoInterval)
-            ASMAtomicWriteBool(&pTimer->fSuspended, true);
-        pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
+
+        if (pTimer->u64NanoInterval)
+        {
+            /*
+             * Recurring timer.
+             */
+            for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
+                if (    RTCpuSetIsMemberByIndex(&OnlineSet, iCpu)
+                    &&  iCpuSelf != iCpu)
+                    KeInsertQueueDpc(&pTimer->aSubTimers[iCpu].NtDpc, 0, 0);
+
+            uint64_t iTick = ++pSubTimer->iTick;
+            rtTimerNtRearmInternval(pTimer, iTick, &pTimer->aSubTimers[RTMpCpuIdToSetIndex(pTimer->idCpu)].NtDpc);
+            pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
+        }
+        else
+        {
+            /*
+             * Single shot timers gets complicated wrt to fSuspended maintance.
+             */
+            uint32_t cCpus = 0;
+            for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
+                if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
+                    cCpus++;
+            ASMAtomicAddS32(&pTimer->cOmniSuspendCountDown, cCpus);
+
+            for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
+                if (    RTCpuSetIsMemberByIndex(&OnlineSet, iCpu)
+                    &&  iCpuSelf != iCpu)
+                    if (!KeInsertQueueDpc(&pTimer->aSubTimers[iCpu].NtDpc, 0, 0))
+                        ASMAtomicDecS32(&pTimer->cOmniSuspendCountDown); /* already queued and counted. */
+
+            if (ASMAtomicDecS32(&pTimer->cOmniSuspendCountDown) <= 0)
+                ASMAtomicWriteBool(&pTimer->fSuspended, true);
+
+            pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
+        }
     }
 
@@ -239,4 +337,5 @@
                      : &pTimer->aSubTimers[0].NtDpc;
 
+#ifndef RTR0TIMER_NT_MANUAL_RE_ARM
     uint64_t u64Interval = pTimer->u64NanoInterval / 1000000; /* This is ms, believe it or not. */
     ULONG ulInterval = (ULONG)u64Interval;
@@ -245,4 +344,5 @@
     else if (!ulInterval && pTimer->u64NanoInterval)
         ulInterval = 1;
+#endif
 
     LARGE_INTEGER DueTime;
@@ -254,6 +354,12 @@
     for (unsigned iCpu = 0; iCpu < cSubTimers; iCpu++)
         pTimer->aSubTimers[iCpu].iTick = 0;
+    ASMAtomicWriteS32(&pTimer->cOmniSuspendCountDown, 0);
     ASMAtomicWriteBool(&pTimer->fSuspended, false);
+#ifdef RTR0TIMER_NT_MANUAL_RE_ARM
+    pTimer->uNtStartTime = rtTimerNtQueryInterruptTime();
+    KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, pMasterDpc);
+#else
     KeSetTimerEx(&pTimer->NtTimer, DueTime, ulInterval, pMasterDpc);
+#endif
     return VINF_SUCCESS;
 }
@@ -369,4 +475,5 @@
      */
     pTimer->u32Magic = RTTIMER_MAGIC;
+    pTimer->cOmniSuspendCountDown = 0;
     pTimer->fSuspended = true;
     pTimer->fSpecificCpu = (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC) && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL;
