[STORPORT] Fix x64 build
[reactos.git] / ntoskrnl / ke / time.c
index 49ca79d..ef92051 100644 (file)
@@ -20,6 +20,45 @@ BOOLEAN KiTimeAdjustmentEnabled = FALSE;
 
 /* FUNCTIONS ******************************************************************/
 
+FORCEINLINE
+VOID
+KiWriteSystemTime(volatile KSYSTEM_TIME *SystemTime, ULARGE_INTEGER NewTime)
+{
+#ifdef _WIN64
+    /* Do a single atomic write */
+    *(ULONGLONG*)SystemTime = NewTime.QuadPart;
+#else
+    /* Update in 3 steps, so that a reader can recognize partial updates */
+    SystemTime->High1Time = NewTime.HighPart;
+    SystemTime->LowPart = NewTime.LowPart;
+    SystemTime->High2Time = NewTime.HighPart;
+#endif
+}
+
+FORCEINLINE
+VOID
+KiCheckForTimerExpiration(
+    PKPRCB Prcb,
+    PKTRAP_FRAME TrapFrame,
+    ULARGE_INTEGER InterruptTime)
+{
+    ULONG Hand;
+
+    /* Check for timer expiration */
+    Hand = KeTickCount.LowPart & (TIMER_TABLE_SIZE - 1);
+    if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
+    {
+        /* Check if we are already doing expiration */
+        if (!Prcb->TimerRequest)
+        {
+            /* Request a DPC to handle this */
+            Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
+            Prcb->TimerHand = Hand;
+            HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
+        }
+    }
+}
+
 VOID
 FASTCALL
 KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
@@ -28,88 +67,67 @@ KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
 {
     PKPRCB Prcb = KeGetCurrentPrcb();
     ULARGE_INTEGER CurrentTime, InterruptTime;
-    ULONG Hand, OldTickCount;
+    LONG OldTickOffset;
+
+    /* Check if this tick is being skipped */
+    if (Prcb->SkipTick)
+    {
+        /* Handle it next time */
+        Prcb->SkipTick = FALSE;
+
+        /* Increase interrupt count and end the interrupt */
+        Prcb->InterruptCount++;
+        KiEndInterrupt(Irql, TrapFrame);
+
+        /* Note: non-x86 return back to the caller! */
+        return;
+    }
 
     /* Add the increment time to the shared data */
-    InterruptTime.HighPart = SharedUserData->InterruptTime.High1Time;
-    InterruptTime.LowPart = SharedUserData->InterruptTime.LowPart;
+    InterruptTime.QuadPart = *(ULONGLONG*)&SharedUserData->InterruptTime;
     InterruptTime.QuadPart += Increment;
-    SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
-    SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
-    SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
+    KiWriteSystemTime(&SharedUserData->InterruptTime, InterruptTime);
+
+    /* Check for timer expiration */
+    KiCheckForTimerExpiration(Prcb, TrapFrame, InterruptTime);
+
+    /* Update the tick offset */
+    OldTickOffset = InterlockedExchangeAdd(&KiTickOffset, -(LONG)Increment);
 
-    /* Update tick count */
-    InterlockedExchangeAdd(&KiTickOffset, -(LONG)Increment);
+    /* If the debugger is enabled, check for break-in request */
+    if (KdDebuggerEnabled && KdPollBreakIn())
+    {
+        /* Break-in requested! */
+        DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
+    }
 
-    /* Check for incomplete tick */
-    OldTickCount = KeTickCount.LowPart;
-    if (KiTickOffset <= 0)
+    /* Check for full tick */
+    if (OldTickOffset <= (LONG)Increment)
     {
         /* Update the system time */
-        CurrentTime.HighPart = SharedUserData->SystemTime.High1Time;
-        CurrentTime.LowPart = SharedUserData->SystemTime.LowPart;
+        CurrentTime.QuadPart = *(ULONGLONG*)&SharedUserData->SystemTime;
         CurrentTime.QuadPart += KeTimeAdjustment;
-        SharedUserData->SystemTime.High2Time = CurrentTime.HighPart;
-        SharedUserData->SystemTime.LowPart = CurrentTime.LowPart;
-        SharedUserData->SystemTime.High1Time = CurrentTime.HighPart;
+        KiWriteSystemTime(&SharedUserData->SystemTime, CurrentTime);
 
         /* Update the tick count */
-        CurrentTime.HighPart = KeTickCount.High1Time;
-        CurrentTime.LowPart = OldTickCount;
-        CurrentTime.QuadPart += 1;
-        KeTickCount.High2Time = CurrentTime.HighPart;
-        KeTickCount.LowPart = CurrentTime.LowPart;
-        KeTickCount.High1Time = CurrentTime.HighPart;
+        CurrentTime.QuadPart = (*(ULONGLONG*)&KeTickCount) + 1;
+        KiWriteSystemTime(&KeTickCount, CurrentTime);
 
         /* Update it in the shared user data */
-        SharedUserData->TickCount.High2Time = CurrentTime.HighPart;
-        SharedUserData->TickCount.LowPart = CurrentTime.LowPart;
-        SharedUserData->TickCount.High1Time = CurrentTime.HighPart;
-
-        /* Check for timer expiration */
-        Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
-        if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
-        {
-            /* Check if we are already doing expiration */
-            if (!Prcb->TimerRequest)
-            {
-                /* Request a DPC to handle this */
-                Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
-                Prcb->TimerHand = Hand;
-                HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
-            }
-        }
+        KiWriteSystemTime(&SharedUserData->TickCount, CurrentTime);
 
         /* Check for expiration with the new tick count as well */
-        OldTickCount++;
-    }
-
-    /* Check for timer expiration */
-    Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
-    if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
-    {
-        /* Check if we are already doing expiration */
-        if (!Prcb->TimerRequest)
-        {
-            /* Request a DPC to handle this */
-            Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
-            Prcb->TimerHand = Hand;
-            HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
-        }
-    }
+        KiCheckForTimerExpiration(Prcb, TrapFrame, InterruptTime);
 
-    /* Check if this was a full tick */
-    if (KiTickOffset <= 0)
-    {
-        /* Update the tick offset */
+        /* Reset the tick offset */
         KiTickOffset += KeMaximumIncrement;
 
-        /* Update system runtime */
+        /* Update processor/thread runtime */
         KeUpdateRunTime(TrapFrame, Irql);
     }
     else
     {
-        /* Increase interrupt count and exit */
+        /* Increase interrupt count only */
         Prcb->InterruptCount++;
     }
 
@@ -125,12 +143,20 @@ KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
     PKTHREAD Thread = KeGetCurrentThread();
     PKPRCB Prcb = KeGetCurrentPrcb();
 
+    /* Check if this tick is being skipped */
+    if (Prcb->SkipTick)
+    {
+        /* Handle it next time */
+        Prcb->SkipTick = FALSE;
+        return;
+    }
+
     /* Increase interrupt count */
     Prcb->InterruptCount++;
 
     /* Check if we came from user mode */
 #ifndef _M_ARM
-    if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
+    if (KiUserTrap(TrapFrame) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
 #else
     if (TrapFrame->PreviousMode == UserMode)
 #endif
@@ -157,6 +183,24 @@ KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
         {
             /* Handle being in a DPC */
             Prcb->DpcTime++;
+
+#if DBG
+            /* Update the DPC time */
+            Prcb->DebugDpcTime++;
+
+            /* Check if we have timed out */
+            if (Prcb->DebugDpcTime == KiDPCTimeout)
+            {
+                /* We did! */
+                DbgPrint("*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime\n");
+
+                /* Break if debugger is enabled */
+                if (KdDebuggerEnabled) DbgBreakPoint();
+
+                /* Clear state */
+                Prcb->DebugDpcTime = 0;
+            }
+#endif
         }
     }