diff --git a/dll/ntdll/rtl/libsupp.c b/dll/ntdll/rtl/libsupp.c index 75618a76951..5599c7f6501 100644 --- a/dll/ntdll/rtl/libsupp.c +++ b/dll/ntdll/rtl/libsupp.c @@ -1221,22 +1221,9 @@ ULONG NTAPI RtlGetTickCount(VOID) { - ULARGE_INTEGER TickCount; + LARGE_INTEGER TickCount; -#ifdef _WIN64 - TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount); -#else - while (TRUE) - { - TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time; - TickCount.LowPart = SharedUserData->TickCount.LowPart; - - if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time) - break; - - YieldProcessor(); - } -#endif + TickCount = KiReadSystemTime(&SharedUserData->TickCount); return (ULONG)((UInt32x32To64(TickCount.LowPart, SharedUserData->TickCountMultiplier) >> 24) + diff --git a/dll/win32/kernel32/client/time.c b/dll/win32/kernel32/client/time.c index 7c67e1165ce..f0b716ec141 100644 --- a/dll/win32/kernel32/client/time.c +++ b/dll/win32/kernel32/client/time.c @@ -129,12 +129,7 @@ GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime) { LARGE_INTEGER SystemTime; - do - { - SystemTime.HighPart = SharedUserData->SystemTime.High1Time; - SystemTime.LowPart = SharedUserData->SystemTime.LowPart; - } - while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time); + SystemTime = KiReadSystemTime(&SharedUserData->SystemTime); lpFileTime->dwLowDateTime = SystemTime.LowPart; lpFileTime->dwHighDateTime = SystemTime.HighPart; @@ -227,12 +222,8 @@ FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime, TimePtr = IsTimeZoneRedirectionEnabled() ? &BaseStaticServerData->ktTermsrvClientBias : &SharedUserData->TimeZoneBias; - do - { - TimeZoneBias.HighPart = TimePtr->High1Time; - TimeZoneBias.LowPart = TimePtr->LowPart; - } - while (TimeZoneBias.HighPart != TimePtr->High2Time); + + TimeZoneBias = KiReadSystemTime(TimePtr); FileTime.LowPart = lpFileTime->dwLowDateTime; FileTime.HighPart = lpFileTime->dwHighDateTime; @@ -260,12 +251,7 @@ LocalFileTimeToFileTime(IN CONST FILETIME *lpLocalFileTime, &BaseStaticServerData->ktTermsrvClientBias : &SharedUserData->TimeZoneBias; - do - { - TimeZoneBias.HighPart = TimePtr->High1Time; - TimeZoneBias.LowPart = TimePtr->LowPart; - } - while (TimeZoneBias.HighPart != TimePtr->High2Time); + TimeZoneBias = KiReadSystemTime(TimePtr); FileTime.LowPart = lpLocalFileTime->dwLowDateTime; FileTime.HighPart = lpLocalFileTime->dwHighDateTime; @@ -289,22 +275,13 @@ GetLocalTime(OUT LPSYSTEMTIME lpSystemTime) TIME_FIELDS TimeFields; volatile KSYSTEM_TIME *TimePtr; - do - { - SystemTime.HighPart = SharedUserData->SystemTime.High1Time; - SystemTime.LowPart = SharedUserData->SystemTime.LowPart; - } - while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time); + SystemTime = KiReadSystemTime(&SharedUserData->SystemTime); TimePtr = IsTimeZoneRedirectionEnabled() ? &BaseStaticServerData->ktTermsrvClientBias : &SharedUserData->TimeZoneBias; - do - { - TimeZoneBias.HighPart = TimePtr->High1Time; - TimeZoneBias.LowPart = TimePtr->LowPart; - } - while (TimeZoneBias.HighPart != TimePtr->High2Time); + + TimeZoneBias = KiReadSystemTime(TimePtr); SystemTime.QuadPart -= TimeZoneBias.QuadPart; RtlTimeToTimeFields(&SystemTime, &TimeFields); diff --git a/dll/win32/kernel32/kernel32_vista/GetTickCount64.c b/dll/win32/kernel32/kernel32_vista/GetTickCount64.c index 4d395350876..bc185143721 100644 --- a/dll/win32/kernel32/kernel32_vista/GetTickCount64.c +++ b/dll/win32/kernel32/kernel32_vista/GetTickCount64.c @@ -8,18 +8,11 @@ ULONGLONG WINAPI GetTickCount64(VOID) { - ULARGE_INTEGER TickCount; + LARGE_INTEGER TickCount; - while (TRUE) - { - TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time; - TickCount.LowPart = SharedUserData->TickCount.LowPart; + TickCount = KiReadSystemTime(&SharedUserData->TickCount); - if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time) break; - - YieldProcessor(); - } - - return (UInt32x32To64(TickCount.LowPart, SharedUserData->TickCountMultiplier) >> 24) + - (UInt32x32To64(TickCount.HighPart, SharedUserData->TickCountMultiplier) << 8); + ULONG TickCountMultiplier = SharedUserData->TickCountMultiplier; + return (UInt32x32To64(TickCount.LowPart, TickCountMultiplier) >> 24) + + (UInt32x32To64(TickCount.HighPart, TickCountMultiplier) << 8); } diff --git a/ntoskrnl/ex/init.c b/ntoskrnl/ex/init.c index 16c0eb8d4a2..83e0d9b62fe 100644 --- a/ntoskrnl/ex/init.c +++ b/ntoskrnl/ex/init.c @@ -1550,9 +1550,7 @@ Phase1InitializationDiscard(IN PVOID Context) 10000000); /* Set the boot time-zone bias */ - SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.HighPart; - SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.LowPart; - SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.HighPart; + KiWriteSystemTime(&SharedUserData->TimeZoneBias, ExpTimeZoneBias); /* Convert the boot time to local time, and set it */ UniversalBootTime.QuadPart = SystemBootTime.QuadPart + diff --git a/ntoskrnl/ex/time.c b/ntoskrnl/ex/time.c index 56c01624ee1..c812d040609 100644 --- a/ntoskrnl/ex/time.c +++ b/ntoskrnl/ex/time.c @@ -336,9 +336,7 @@ ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime) ExpTimeZoneBias = NewTimeZoneBias; /* Change SharedUserData->TimeZoneBias for user-mode applications */ - SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart; - SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart; - SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart; + KiWriteSystemTime(&SharedUserData->TimeZoneBias, ExpTimeZoneBias); SharedUserData->TimeZoneId = ExpTimeZoneId; /* Convert boot time from local time to UTC */ @@ -349,9 +347,7 @@ ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime) /* Change it for user-mode applications */ CurrentTime.QuadPart += ExpTimeZoneBias.QuadPart; - SharedUserData->SystemTime.High2Time = CurrentTime.u.HighPart; - SharedUserData->SystemTime.LowPart = CurrentTime.u.LowPart; - SharedUserData->SystemTime.High1Time = CurrentTime.u.HighPart; + KiWriteSystemTime(&SharedUserData->SystemTime, CurrentTime); /* Return success */ return TRUE; @@ -424,9 +420,7 @@ ExpSetTimeZoneInformation(PRTL_TIME_ZONE_INFORMATION TimeZoneInformation) sizeof(RTL_TIME_ZONE_INFORMATION)); /* Set the new time zone information */ - SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart; - SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart; - SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart; + KiWriteSystemTime(&SharedUserData->TimeZoneBias, ExpTimeZoneBias); SharedUserData->TimeZoneId = ExpTimeZoneId; DPRINT("New time zone bias: %I64d minutes\n", diff --git a/ntoskrnl/ke/clock.c b/ntoskrnl/ke/clock.c index aaed4d14677..249cd32c697 100644 --- a/ntoskrnl/ke/clock.c +++ b/ntoskrnl/ke/clock.c @@ -55,9 +55,7 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime, KeQuerySystemTime(OldTime); /* Set the new system time (ordering of these operations is critical) */ - SharedUserData->SystemTime.High2Time = NewTime->HighPart; - SharedUserData->SystemTime.LowPart = NewTime->LowPart; - SharedUserData->SystemTime.High1Time = NewTime->HighPart; + KiWriteSystemTime(&SharedUserData->SystemTime, *NewTime); /* Check if this was for the HAL and set the RTC time */ if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields); @@ -164,15 +162,7 @@ VOID NTAPI KeQueryTickCount(IN PLARGE_INTEGER TickCount) { - /* Loop until we get a perfect match */ - for (;;) - { - /* Read the tick count value */ - TickCount->HighPart = KeTickCount.High1Time; - TickCount->LowPart = KeTickCount.LowPart; - if (TickCount->HighPart == KeTickCount.High2Time) break; - YieldProcessor(); - } + *TickCount = KiReadSystemTime(&KeTickCount); } #ifndef _M_AMD64 diff --git a/ntoskrnl/ke/time.c b/ntoskrnl/ke/time.c index cb10259bb65..f741c7593d2 100644 --- a/ntoskrnl/ke/time.c +++ b/ntoskrnl/ke/time.c @@ -20,33 +20,18 @@ 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; -#endif - SystemTime->High2Time = NewTime.HighPart; -} - FORCEINLINE VOID KiCheckForTimerExpiration( PKPRCB Prcb, PKTRAP_FRAME TrapFrame, - ULARGE_INTEGER InterruptTime) + LARGE_INTEGER InterruptTime) { ULONG Hand; /* Check for timer expiration */ Hand = KeTickCount.LowPart & (TIMER_TABLE_SIZE - 1); - if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart) + if (KiTimerTableListHead[Hand].Time.QuadPart <= (ULONG64)InterruptTime.QuadPart) { /* Check if we are already doing expiration */ if (!Prcb->TimerRequest) @@ -66,7 +51,7 @@ KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame, IN KIRQL Irql) { PKPRCB Prcb = KeGetCurrentPrcb(); - ULARGE_INTEGER CurrentTime, InterruptTime; + LARGE_INTEGER CurrentTime, InterruptTime; LONG OldTickOffset; /* Check if this tick is being skipped */ diff --git a/sdk/include/ndk/kefuncs.h b/sdk/include/ndk/kefuncs.h index f1ac4888be8..2b89f08ec71 100644 --- a/sdk/include/ndk/kefuncs.h +++ b/sdk/include/ndk/kefuncs.h @@ -394,6 +394,58 @@ KeRaiseUserException( #endif +#ifndef NONAMELESSUNION + +FORCEINLINE +LARGE_INTEGER +KiReadSystemTime( + _In_ volatile const KSYSTEM_TIME *SystemTime) +{ + LARGE_INTEGER Time; + +#ifdef _WIN64 + /* Do a single atomic read */ + Time.QuadPart = *(volatile ULONG64*)SystemTime; +#else + /* Read in a loop until we get a match */ + for (;;) + { + Time.HighPart = SystemTime->High1Time; + Time.LowPart = SystemTime->LowPart; + if (Time.HighPart == SystemTime->High2Time) break; + YieldProcessor(); + } +#endif + return Time; +} + +#ifndef NTOS_MODE_USER + +FORCEINLINE +VOID +KiWriteSystemTime( + _Out_ volatile KSYSTEM_TIME *SystemTime, + _In_ LARGE_INTEGER NewTime) +{ + /* Update High2Time first to indicate an update in progress */ + SystemTime->High2Time = NewTime.HighPart; + +#ifdef _WIN64 + /* Do a single 'atomic' write. This isn't actually guaranteed to be atomic, + if the address isn't 64 bit aligned. But as long as the entire 64 bits + are within a single cache line, we should be good (on x64 at least, + when it comes to ARM64, all bets are off) This is also what Windows does. */ + *(LONGLONG*)SystemTime = NewTime.QuadPart; +#else + /* Update low part, then high part to allow readers detect partial updates. */ + SystemTime->LowPart = NewTime.LowPart; + SystemTime->High1Time = NewTime.HighPart; +#endif +} + +#endif // !NTOS_MODE_USER +#endif // !NONAMELESSUNION + // // Native Calls //