Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 7a0f6ca

Browse files
authored
Support System.Runtime.Caching on Linux (#26354)
* Support System.Runtime.Caching on Linux The only significant difference with Windows is that an attempt to set PhysicalMemoryLimitPercentage config parameter will result in PNSE on Linux as we don't support a notion of memory pressure on Linux yet. * Addressing PR feedback * Enabling System.Runtime.Caching on Linux: - split platform dependent classes to partial ones and updated the project - updated tests to be able to run them on Unix - addressing feedback - fixing build issues on Unix * Removing package configuration * Updating Configurations.props * Fixing netstandard configuration build for the implementation by throwing PNS
1 parent 250ba41 commit 7a0f6ca

File tree

11 files changed

+154
-85
lines changed

11 files changed

+154
-85
lines changed

src/System.Runtime.Caching/src/Configurations.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
<PackageConfigurations>
55
netstandard;
66
netcoreapp2.0-Windows_NT;
7+
netcoreapp2.0-Unix;
78
</PackageConfigurations>
89
<BuildConfigurations>
910
$(PackageConfigurations);
1011
netcoreapp-Windows_NT;
12+
netcoreapp-Unix;
1113
_netfx;
1214
</BuildConfigurations>
1315
</PropertyGroup>

src/System.Runtime.Caching/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,7 @@
183183
<data name="PlatformNotSupported_Caching" xml:space="preserve">
184184
<value>System.Runtime.Caching is not supported on this platform.</value>
185185
</data>
186+
<data name="PlatformNotSupported_PhysicalMemoryLimitPercentage" xml:space="preserve">
187+
<value>The PhysicalMemoryLimitPercentage parameter is not supported on this platform.</value>
188+
</data>
186189
</root>

src/System.Runtime.Caching/src/System.Runtime.Caching.csproj

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
88
<!-- Although we have a netstandard configuration, we know we are not currently UAP compatible-->
99
<UWPCompatible>false</UWPCompatible>
10-
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetsWindows)' != 'true'">SR.PlatformNotSupported_Caching</GeneratePlatformNotSupportedAssemblyMessage>
10+
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard'">SR.PlatformNotSupported_Caching</GeneratePlatformNotSupportedAssemblyMessage>
1111
</PropertyGroup>
1212
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
1313
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
1414
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Debug|AnyCPU'" />
1515
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Release|AnyCPU'" />
1616
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
1717
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
18-
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
18+
<ItemGroup Condition="'$(TargetGroup)' != 'netstandard'">
1919
<Compile Include="System\Runtime\Caching\_shims.cs" />
2020
<Compile Include="System\Runtime\Caching\CacheEntryChangeMonitor.cs" />
2121
<Compile Include="System\Runtime\Caching\CacheEntryRemovedArguments.cs" />
@@ -59,6 +59,10 @@
5959
<Compile Include="System\Runtime\Caching\Hosting\IFileChangeNotificationSystem.cs" />
6060
<Compile Include="System\Runtime\Caching\Hosting\IMemoryCacheManager.cs" />
6161
<Compile Include="System\Runtime\Caching\Resources\RH.cs" />
62+
</ItemGroup>
63+
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
64+
<Compile Include="System\Runtime\Caching\MemoryMonitor.Windows.cs" />
65+
<Compile Include="System\Runtime\Caching\PhysicalMemoryMonitor.Windows.cs" />
6266
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GlobalMemoryStatusEx.cs">
6367
<Link>Common\Interop\Windows\kernel32\Interop.GlobalMemoryStatusEx.cs</Link>
6468
</Compile>
@@ -69,6 +73,9 @@
6973
<Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
7074
</Compile>
7175
</ItemGroup>
76+
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
77+
<Compile Include="System\Runtime\Caching\PhysicalMemoryMonitor.Unix.cs" />
78+
</ItemGroup>
7279
<ItemGroup>
7380
<Reference Include="Microsoft.Win32.Primitives" />
7481
<Reference Include="Microsoft.Win32.Registry" />
@@ -90,6 +97,7 @@
9097
<Reference Include="System.Runtime" />
9198
<Reference Include="System.Runtime.Extensions" />
9299
<Reference Include="System.Runtime.InteropServices" />
100+
<Reference Include="System.Runtime.InteropServices.RuntimeInformation" />
93101
<Reference Include="System.Security.Permissions" />
94102
<Reference Include="System.Security.Principal.Windows" />
95103
<Reference Include="System.Threading" />

src/System.Runtime.Caching/src/System/Runtime/Caching/Dbg.cs

Lines changed: 43 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -413,29 +413,35 @@ public static void OnRegChangeKeyValue(object state, bool timedOut) {
413413
}
414414

415415
private static void MonitorRegistryForOneChange() {
416-
// Close the open reg handle
417-
if (s_regHandle != null) {
418-
s_regHandle.Close();
419-
s_regHandle = null;
420-
}
416+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
417+
{
418+
// Close the open reg handle
419+
if (s_regHandle != null)
420+
{
421+
s_regHandle.Close();
422+
s_regHandle = null;
423+
}
421424

422-
// Open the reg key
423-
int result = NativeMethods.RegOpenKeyEx(NativeMethods.HKEY_LOCAL_MACHINE, s_listenKeyName, 0, NativeMethods.KEY_READ, out s_regHandle);
424-
if (result != 0) {
425-
StopRegistryMonitor();
426-
return;
427-
}
425+
// Open the reg key
426+
int result = NativeMethods.RegOpenKeyEx(NativeMethods.HKEY_LOCAL_MACHINE, s_listenKeyName, 0, NativeMethods.KEY_READ, out s_regHandle);
427+
if (result != 0)
428+
{
429+
StopRegistryMonitor();
430+
return;
431+
}
428432

429-
// Listen for changes.
430-
result = NativeMethods.RegNotifyChangeKeyValue(
431-
s_regHandle,
432-
true,
433-
NativeMethods.REG_NOTIFY_CHANGE_NAME | NativeMethods.REG_NOTIFY_CHANGE_LAST_SET,
434-
s_notifyEvent.SafeWaitHandle,
435-
true);
433+
// Listen for changes.
434+
result = NativeMethods.RegNotifyChangeKeyValue(
435+
s_regHandle,
436+
true,
437+
NativeMethods.REG_NOTIFY_CHANGE_NAME | NativeMethods.REG_NOTIFY_CHANGE_LAST_SET,
438+
s_notifyEvent.SafeWaitHandle,
439+
true);
436440

437-
if (result != 0) {
438-
StopRegistryMonitor();
441+
if (result != 0)
442+
{
443+
StopRegistryMonitor();
444+
}
439445
}
440446
}
441447

@@ -523,8 +529,11 @@ private static bool TraceBreak(string tagName, string message, Exception e, bool
523529
}
524530
else {
525531
if (s_includeThreadPrefix) {
526-
idThread = NativeMethods.GetCurrentThreadId();
527-
idProcess = NativeMethods.GetCurrentProcessId();
532+
idThread = Thread.CurrentThread.ManagedThreadId;
533+
using(var process = Process.GetCurrentProcess())
534+
{
535+
idProcess = process.Id;
536+
}
528537
traceFormat = "[0x{0:x}.{1:x} {2} {3}] {4}\n{5}";
529538
}
530539
else {
@@ -610,42 +619,21 @@ static bool DoAssert(string message) {
610619
611620
A=Exit process R=Debug I=Continue";
612621
}
622+
int idProcess = 0;
623+
using (var process = Process.GetCurrentProcess())
624+
{
625+
idProcess = process.Id;
626+
}
613627

614628
string dialogMessage = string.Format(
615629
CultureInfo.InvariantCulture,
616630
dialogFormat,
617631
message,
618632
fileName, lineNumber,
619633
COMPONENT,
620-
NativeMethods.GetCurrentProcessId(), NativeMethods.GetCurrentThreadId(),
634+
idProcess, Thread.CurrentThread.ManagedThreadId,
621635
trace.ToString());
622636

623-
//MBResult mbResult = new MBResult();
624-
625-
//Thread thread = new Thread(
626-
// delegate() {
627-
// for (int i = 0; i < 100; i++) {
628-
// NativeMethods.MSG msg = new NativeMethods.MSG();
629-
// NativeMethods.PeekMessage(ref msg, new HandleRef(mbResult, IntPtr.Zero), 0, 0, NativeMethods.PM_REMOVE);
630-
// }
631-
632-
// mbResult.Result = NativeMethods.MessageBox(new HandleRef(mbResult, IntPtr.Zero), dialogMessage, PRODUCT + " Assertion",
633-
// NativeMethods.MB_SERVICE_NOTIFICATION |
634-
// NativeMethods.MB_TOPMOST |
635-
// NativeMethods.MB_ABORTRETRYIGNORE |
636-
// NativeMethods.MB_ICONEXCLAMATION);
637-
// }
638-
//);
639-
640-
//thread.Start();
641-
//thread.Join();
642-
643-
//if (mbResult.Result == NativeMethods.IDABORT) {
644-
// IntPtr currentProcess = NativeMethods.GetCurrentProcess();
645-
// NativeMethods.TerminateProcess(new HandleRef(mbResult, currentProcess), 1);
646-
//}
647-
648-
//return mbResult.Result == NativeMethods.IDRETRY;
649637
Debug.Fail(dialogMessage);
650638
return true;
651639
}
@@ -826,13 +814,16 @@ internal static bool IsTagPresent(string tagName)
826814
internal static void Break()
827815
{
828816
#if DEBUG
829-
if (NativeMethods.IsDebuggerPresent()) {
817+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && NativeMethods.IsDebuggerPresent())
818+
{
830819
NativeMethods.DebugBreak();
831820
}
832-
else if (!Debugger.IsAttached) {
821+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Debugger.IsAttached)
822+
{
833823
Debugger.Launch();
834824
}
835-
else {
825+
else
826+
{
836827
Debugger.Break();
837828
}
838829
#endif

src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryCacheStatistics.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ private void InitializeConfiguration(NameValueCollection config)
147147
_configCacheMemoryLimitMegabytes = ConfigUtil.GetIntValue(config, ConfigUtil.CacheMemoryLimitMegabytes, _configCacheMemoryLimitMegabytes, true, Int32.MaxValue);
148148
_configPhysicalMemoryLimitPercentage = ConfigUtil.GetIntValue(config, ConfigUtil.PhysicalMemoryLimitPercentage, _configPhysicalMemoryLimitPercentage, true, 100);
149149
}
150+
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _configPhysicalMemoryLimitPercentage > 0)
151+
{
152+
throw new PlatformNotSupportedException(SR.PlatformNotSupported_PhysicalMemoryLimitPercentage);
153+
}
150154
}
151155

152156
private void InitDisposableMembers()
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Specialized;
7+
using System.Security;
8+
using System.Runtime.InteropServices;
9+
10+
11+
namespace System.Runtime.Caching
12+
{
13+
internal abstract partial class MemoryMonitor
14+
{
15+
static MemoryMonitor()
16+
{
17+
Interop.Kernel32.MEMORYSTATUSEX memoryStatusEx = default;
18+
memoryStatusEx.dwLength = (uint)Marshal.SizeOf<Interop.Kernel32.MEMORYSTATUSEX>();
19+
if (Interop.Kernel32.GlobalMemoryStatusEx(out memoryStatusEx) != 0)
20+
{
21+
s_totalPhysical = (long)memoryStatusEx.ullTotalPhys;
22+
s_totalVirtual = (long)memoryStatusEx.ullTotalVirtual;
23+
}
24+
}
25+
}
26+
}

src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.cs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace System.Runtime.Caching
1616
// drop cache entries to avoid paging. The second monitors the amount of memory used by
1717
// the cache itself, and helps determine when we should drop cache entries to avoid
1818
// exceeding the cache's memory limit. Both are configurable (see ConfigUtil.cs).
19-
internal abstract class MemoryMonitor
19+
internal abstract partial class MemoryMonitor
2020
{
2121
protected const int TERABYTE_SHIFT = 40;
2222
protected const long TERABYTE = 1L << TERABYTE_SHIFT;
@@ -39,22 +39,11 @@ internal abstract class MemoryMonitor
3939
protected int[] _pressureHist;
4040
protected int _pressureTotal;
4141

42-
private static long s_totalPhysical;
43-
private static long s_totalVirtual;
42+
private static long s_totalPhysical = 0;
43+
private static long s_totalVirtual = 0;
4444

45-
static MemoryMonitor()
46-
{
47-
Interop.Kernel32.MEMORYSTATUSEX memoryStatusEx;
48-
memoryStatusEx.dwLength = (uint)Marshal.SizeOf(typeof(Interop.Kernel32.MEMORYSTATUSEX));
49-
if (Interop.Kernel32.GlobalMemoryStatusEx(out memoryStatusEx) != 0)
50-
{
51-
s_totalPhysical = (long)memoryStatusEx.ullTotalPhys;
52-
s_totalVirtual = (long)memoryStatusEx.ullTotalVirtual;
53-
}
54-
}
55-
56-
internal static long TotalPhysical { get { return s_totalPhysical; } }
57-
internal static long TotalVirtual { get { return s_totalVirtual; } }
45+
internal static long TotalPhysical => s_totalPhysical;
46+
internal static long TotalVirtual => s_totalVirtual;
5847

5948
internal int PressureLast { get { return _pressureHist[_i0]; } }
6049
internal int PressureHigh { get { return _pressureHigh; } }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
7+
namespace System.Runtime.Caching
8+
{
9+
internal sealed partial class PhysicalMemoryMonitor : MemoryMonitor
10+
{
11+
protected override int GetCurrentPressure()
12+
{
13+
return 0;
14+
}
15+
}
16+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Runtime.Caching.Configuration;
7+
using System.Runtime.InteropServices;
8+
using System.Security;
9+
10+
namespace System.Runtime.Caching
11+
{
12+
internal sealed partial class PhysicalMemoryMonitor : MemoryMonitor
13+
{
14+
protected override int GetCurrentPressure()
15+
{
16+
Interop.Kernel32.MEMORYSTATUSEX memoryStatusEx = default;
17+
memoryStatusEx.dwLength = (uint)Marshal.SizeOf<Interop.Kernel32.MEMORYSTATUSEX>();
18+
if (Interop.Kernel32.GlobalMemoryStatusEx(out memoryStatusEx) == 0)
19+
{
20+
return 0;
21+
}
22+
23+
int memoryLoad = (int)memoryStatusEx.dwMemoryLoad;
24+
return memoryLoad;
25+
}
26+
}
27+
}

src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.cs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace System.Runtime.Caching
1212
// PhysicalMemoryMonitor monitors the amound of physical memory used on the machine
1313
// and helps us determine when to drop entries to avoid paging and GC thrashing.
1414
// The limit is configurable (see ConfigUtil.cs).
15-
internal sealed class PhysicalMemoryMonitor : MemoryMonitor
15+
internal sealed partial class PhysicalMemoryMonitor : MemoryMonitor
1616
{
1717
private const int MIN_TOTAL_MEMORY_TRIM_PERCENT = 10;
1818
private static readonly long s_TARGET_TOTAL_MEMORY_TRIM_INTERVAL_TICKS = 5 * TimeSpan.TicksPerMinute;
@@ -48,7 +48,6 @@ 8192 81.92 245.76 819.2
4848
*/
4949

5050
long memory = TotalPhysical;
51-
Dbg.Assert(memory != 0, "memory != 0");
5251
if (memory >= 0x100000000)
5352
{
5453
_pressureHigh = 99;
@@ -76,19 +75,6 @@ 8192 81.92 245.76 819.2
7675
InitHistory();
7776
}
7877

79-
protected override int GetCurrentPressure()
80-
{
81-
Interop.Kernel32.MEMORYSTATUSEX memoryStatusEx = default;
82-
memoryStatusEx.dwLength = (uint)Marshal.SizeOf(typeof(Interop.Kernel32.MEMORYSTATUSEX));
83-
if (Interop.Kernel32.GlobalMemoryStatusEx(out memoryStatusEx) == 0)
84-
{
85-
return 0;
86-
}
87-
88-
int memoryLoad = (int)memoryStatusEx.dwMemoryLoad;
89-
return memoryLoad;
90-
}
91-
9278
internal override int GetPercentToTrim(DateTime lastTrimTime, int lastTrimPercent)
9379
{
9480
int percent = 0;

0 commit comments

Comments
 (0)