Skip to content

Commit 6fbd146

Browse files
committed
Refactor GetGetSystemTimeAsFileTimeFnPtr
* Don't check whether `GetSystemTimePreciseAsFileTime` exists, it is always available in `win8`. * Move PInvokes to `Interop.Kernel32`. * Don't use `Math.Abs` to avoid unecessary overflow check.
1 parent d0913fc commit 6fbd146

File tree

4 files changed

+65
-29
lines changed

4 files changed

+65
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.InteropServices;
5+
6+
internal static partial class Interop
7+
{
8+
internal static partial class Kernel32
9+
{
10+
// https://learn.microsoft.com/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime
11+
[LibraryImport(Libraries.Kernel32)]
12+
[SuppressGCTransition]
13+
internal static unsafe partial void GetSystemTimeAsFileTime(
14+
// [NativeTypeName("LPFILETIME")]
15+
ulong* lpSystemTimeAsFileTime);
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.InteropServices;
5+
6+
internal static partial class Interop
7+
{
8+
internal static partial class Kernel32
9+
{
10+
// https://learn.microsoft.com/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
11+
[LibraryImport(Libraries.Kernel32)]
12+
[SuppressGCTransition]
13+
internal static unsafe partial void GetSystemTimePreciseAsFileTime(
14+
// [NativeTypeName("LPFILETIME")]
15+
ulong* lpSystemTimeAsFileTime);
16+
}
17+
}

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

+7-1
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,12 @@
17481748
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetSystemTime.cs">
17491749
<Link>Common\Interop\Windows\Kernel32\Interop.GetSystemTime.cs</Link>
17501750
</Compile>
1751+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetSystemTimeAsFileTime.cs">
1752+
<Link>Common\Interop\Windows\Kernel32\Interop.GetSystemTimeAsFileTime.cs</Link>
1753+
</Compile>
1754+
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetSystemTimePreciseAsFileTime.cs">
1755+
<Link>Common\Interop\Windows\Kernel32\Interop.GetSystemTimePreciseAsFileTime.cs</Link>
1756+
</Compile>
17511757
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetSystemTimes.cs">
17521758
<Link>Common\Interop\Windows\Kernel32\Interop.GetSystemTimes.cs</Link>
17531759
</Compile>
@@ -2602,4 +2608,4 @@
26022608
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnaryPlusOperators.cs" />
26032609
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnsignedNumber.cs" />
26042610
</ItemGroup>
2605-
</Project>
2611+
</Project>

src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs

+24-28
Original file line numberDiff line numberDiff line change
@@ -142,39 +142,35 @@ private static unsafe bool GetSystemSupportsLeapSeconds()
142142

143143
private static unsafe delegate* unmanaged[SuppressGCTransition]<ulong*, void> GetGetSystemTimeAsFileTimeFnPtr()
144144
{
145-
IntPtr kernel32Lib = Interop.Kernel32.LoadLibraryEx(Interop.Libraries.Kernel32, IntPtr.Zero, Interop.Kernel32.LOAD_LIBRARY_SEARCH_SYSTEM32);
146-
Debug.Assert(kernel32Lib != IntPtr.Zero);
147-
148-
IntPtr pfnGetSystemTime = NativeLibrary.GetExport(kernel32Lib, "GetSystemTimeAsFileTime");
149-
150-
if (NativeLibrary.TryGetExport(kernel32Lib, "GetSystemTimePreciseAsFileTime", out IntPtr pfnGetSystemTimePrecise))
145+
const long TargetAccuracy = 100 * TicksPerMillisecond;
146+
147+
delegate* unmanaged[SuppressGCTransition]<ulong*, void> pfnGetSystemTime, pfnGetSystemTimePrecise;
148+
pfnGetSystemTime = &Interop.Kernel32.GetSystemTimeAsFileTime;
149+
pfnGetSystemTimePrecise = &Interop.Kernel32.GetSystemTimePreciseAsFileTime;
150+
151+
// We would like to use GetSystemTimePreciseAsFileTime.
152+
// However, on misconfigured systems, it's possible for the "precise" time to be inaccurate:
153+
// https://github.com/dotnet/runtime/issues/9014
154+
// If it's inaccurate, though, we expect it to be wildly inaccurate, so as a workaround/heuristic,
155+
// we get both the "normal" and "precise" times, and as long as they're close, we use the precise one.
156+
// This workaround can be removed when we better understand what's causing the drift
157+
// and the issue is no longer a problem or can be better worked around on all targeted OSes.
158+
159+
// Retry this check several times to reduce chance of false negatives due to thread being rescheduled
160+
// at wrong time.
161+
for (int i = 10; --i >= 0;)
151162
{
152-
// GetSystemTimePreciseAsFileTime exists and we'd like to use it. However, on
153-
// misconfigured systems, it's possible for the "precise" time to be inaccurate:
154-
// https://github.com/dotnet/runtime/issues/9014
155-
// If it's inaccurate, though, we expect it to be wildly inaccurate, so as a
156-
// workaround/heuristic, we get both the "normal" and "precise" times, and as
157-
// long as they're close, we use the precise one. This workaround can be removed
158-
// when we better understand what's causing the drift and the issue is no longer
159-
// a problem or can be better worked around on all targeted OSes.
160-
161-
// Retry this check several times to reduce chance of false negatives due to thread being rescheduled
162-
// at wrong time.
163-
for (int i = 0; i < 10; i++)
164-
{
165-
long systemTimeResult, preciseSystemTimeResult;
166-
((delegate* unmanaged[SuppressGCTransition]<long*, void>)pfnGetSystemTime)(&systemTimeResult);
167-
((delegate* unmanaged[SuppressGCTransition]<long*, void>)pfnGetSystemTimePrecise)(&preciseSystemTimeResult);
163+
ulong systemTimeResult, preciseSystemTimeResult;
164+
pfnGetSystemTime(&systemTimeResult);
165+
pfnGetSystemTimePrecise(&preciseSystemTimeResult);
168166

169-
if (Math.Abs(preciseSystemTimeResult - systemTimeResult) <= 100 * TicksPerMillisecond)
170-
{
171-
pfnGetSystemTime = pfnGetSystemTimePrecise; // use the precise version
172-
break;
173-
}
167+
if (preciseSystemTimeResult - systemTimeResult + TargetAccuracy <= 2 * TargetAccuracy)
168+
{
169+
return pfnGetSystemTimePrecise;
174170
}
175171
}
176172

177-
return (delegate* unmanaged[SuppressGCTransition]<ulong*, void>)pfnGetSystemTime;
173+
return pfnGetSystemTime;
178174
}
179175

180176
private static unsafe DateTime UpdateLeapSecondCacheAndReturnUtcNow()

0 commit comments

Comments
 (0)