diff --git a/reactos/ntoskrnl/ke/time.c b/reactos/ntoskrnl/ke/time.c index 49ca79d3a4b..1f83b268253 100644 --- a/reactos/ntoskrnl/ke/time.c +++ b/reactos/ntoskrnl/ke/time.c @@ -21,71 +21,31 @@ BOOLEAN KiTimeAdjustmentEnabled = FALSE; /* FUNCTIONS ******************************************************************/ VOID -FASTCALL -KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame, - IN ULONG Increment, - IN KIRQL Irql) +FORCEINLINE +KiWriteSystemTime(volatile KSYSTEM_TIME *SystemTime, ULARGE_INTEGER NewTime) { - PKPRCB Prcb = KeGetCurrentPrcb(); - ULARGE_INTEGER CurrentTime, InterruptTime; - ULONG Hand, OldTickCount; +#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 +} - /* Add the increment time to the shared data */ - InterruptTime.HighPart = SharedUserData->InterruptTime.High1Time; - InterruptTime.LowPart = SharedUserData->InterruptTime.LowPart; - InterruptTime.QuadPart += Increment; - SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart; - SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart; - SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart; - - /* Update tick count */ - InterlockedExchangeAdd(&KiTickOffset, -(LONG)Increment); - - /* Check for incomplete tick */ - OldTickCount = KeTickCount.LowPart; - if (KiTickOffset <= 0) - { - /* Update the system time */ - CurrentTime.HighPart = SharedUserData->SystemTime.High1Time; - CurrentTime.LowPart = SharedUserData->SystemTime.LowPart; - CurrentTime.QuadPart += KeTimeAdjustment; - SharedUserData->SystemTime.High2Time = CurrentTime.HighPart; - SharedUserData->SystemTime.LowPart = CurrentTime.LowPart; - SharedUserData->SystemTime.High1Time = CurrentTime.HighPart; - - /* 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; - - /* 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); - } - } - - /* Check for expiration with the new tick count as well */ - OldTickCount++; - } +VOID +FORCEINLINE +KiCheckForTimerExpiration( + PKPRCB Prcb, + PKTRAP_FRAME TrapFrame, + ULARGE_INTEGER InterruptTime) +{ + ULONG Hand; /* Check for timer expiration */ - Hand = OldTickCount & (TIMER_TABLE_SIZE - 1); + Hand = KeTickCount.LowPart & (TIMER_TABLE_SIZE - 1); if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart) { /* Check if we are already doing expiration */ @@ -97,19 +57,56 @@ KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame, HalRequestSoftwareInterrupt(DISPATCH_LEVEL); } } +} - /* Check if this was a full tick */ - if (KiTickOffset <= 0) +VOID +FASTCALL +KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame, + IN ULONG Increment, + IN KIRQL Irql) +{ + PKPRCB Prcb = KeGetCurrentPrcb(); + ULARGE_INTEGER CurrentTime, InterruptTime; + LONG OldTickOffset; + + /* Add the increment time to the shared data */ + InterruptTime.QuadPart = *(ULONGLONG*)&SharedUserData->InterruptTime; + InterruptTime.QuadPart += Increment; + KiWriteSystemTime(&SharedUserData->InterruptTime, InterruptTime); + + /* Check for timer expiration */ + KiCheckForTimerExpiration(Prcb, TrapFrame, InterruptTime); + + /* Update the tick offset */ + OldTickOffset = InterlockedExchangeAdd(&KiTickOffset, -(LONG)Increment); + + /* Check for full tick */ + if (OldTickOffset <= (LONG)Increment) { - /* Update the tick offset */ + /* Update the system time */ + CurrentTime.QuadPart = *(ULONGLONG*)&SharedUserData->SystemTime; + CurrentTime.QuadPart += KeTimeAdjustment; + KiWriteSystemTime(&SharedUserData->SystemTime, CurrentTime); + + /* Update the tick count */ + CurrentTime.QuadPart = (*(ULONGLONG*)&KeTickCount) + 1; + KiWriteSystemTime(&KeTickCount, CurrentTime); + + /* Update it in the shared user data */ + KiWriteSystemTime(&SharedUserData->TickCount, CurrentTime); + + /* Check for expiration with the new tick count as well */ + KiCheckForTimerExpiration(Prcb, TrapFrame, InterruptTime); + + /* 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++; }