Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/System.Private.CoreLib/System.Private.CoreLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\SafeHandle.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\Loader\AssemblyLoadContext.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\Loader\AssemblyDependencyResolver.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\MemoryFailPoint.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\Serialization\FormatterServices.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\Versioning\CompatibilitySwitch.cs" />
<Compile Include="$(BclSourcesRoot)\System\RuntimeArgumentHandle.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
unsafe internal static bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX buffer)
{
buffer.length = sizeof(MEMORYSTATUSEX);
return GlobalMemoryStatusExNative(ref buffer);
}

[DllImport(Libraries.Kernel32, SetLastError = true, EntryPoint = "GlobalMemoryStatusEx")]
private static extern bool GlobalMemoryStatusExNative(ref MEMORYSTATUSEX buffer);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[StructLayout(LayoutKind.Sequential)]
internal struct MEMORYSTATUSEX
{
// The length field must be set to the size of this data structure.
internal int length;
internal int memoryLoad;
internal ulong totalPhys;
internal ulong availPhys;
internal ulong totalPageFile;
internal ulong availPageFile;
internal ulong totalVirtual;
internal ulong availVirtual;
internal ulong availExtendedVirtual;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct MEMORY_BASIC_INFORMATION
{
internal void* BaseAddress;
internal void* AllocationBase;
internal uint AllocationProtect;
internal UIntPtr RegionSize;
internal uint State;
internal uint Protect;
internal uint Type;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
internal const int MEM_COMMIT = 0x1000;
internal const int MEM_RESERVE = 0x2000;
internal const int MEM_RELEASE = 0x8000;
internal const int MEM_FREE = 0x10000;
internal const int PAGE_READWRITE = 0x04;

[DllImport(Libraries.Kernel32)]
internal static extern unsafe void* VirtualAlloc(void* address, UIntPtr numBytes, int commitOrReserve, int pageProtectionMode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32)]
unsafe internal static extern bool VirtualFree(void* address, UIntPtr numBytes, int pageFreeMode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, SetLastError = true)]
unsafe internal static extern UIntPtr VirtualQuery(void* address, ref MEMORY_BASIC_INFORMATION buffer, UIntPtr sizeOfBuffer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Serialization\StreamingContext.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Versioning\NonVersionableAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Versioning\TargetFrameworkAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SByte.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\AllowPartiallyTrustedCallersAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\CryptographicException.cs" />
Expand Down Expand Up @@ -923,11 +924,15 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetFileType_SafeHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetFullPathNameW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetLongPathNameW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetSystemInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempFileNameW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempPathW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Globalization.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GlobalMemoryStatusEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.LockFile.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MAX_PATH.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MEMORY_BASIC_INFORMATION.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MEMORYSTATUSEX.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MultiByteToWideChar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.OutputDebugString.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs" />
Expand All @@ -939,7 +944,11 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetEnvironmentVariable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetThreadErrorMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SetFilePointerEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.SYSTEM_INFO.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TimeZone.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VirtualAlloc.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VirtualFree.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.VirtualQuery.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WideCharToMultiByte.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_IntPtr.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs" />
Expand Down Expand Up @@ -972,6 +981,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathHelper.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DisableMediaInsertionPrompt.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SafeBSTRHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Windows.cs" />
</ItemGroup>
Expand Down Expand Up @@ -1079,6 +1089,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Unix.cs" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace System.Runtime
{
public sealed partial class MemoryFailPoint
{
private static ulong GetTopOfMemory()
{
// These values are optimistic assumptions. In reality the value will
// often be lower.
return IntPtr.Size == 4 ? uint.MaxValue : ulong.MaxValue;
}

private static bool CheckForAvailableMemory(out ulong availPageFile, out ulong totalAddressSpaceFree)
{
// TODO: Implement
availPageFile = 0;
totalAddressSpaceFree = 0;
return false;
}

// Based on the shouldThrow parameter, this will throw an exception, or
// returns whether there is enough space. In all cases, we update
// our last known free address space, hopefully avoiding needing to
// probe again.
private static bool CheckForFreeAddressSpace(ulong size, bool shouldThrow)
{
// Unreachable until CheckForAvailableMemory is implemented
return false;
}

// Allocate a specified number of bytes, commit them and free them. This should enlarge
// page file if necessary and possible.
private static void GrowPageFileIfNecessaryAndPossible(UIntPtr numBytes)
{
// Unreachable until CheckForAvailableMemory is implemented
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.IO;
using System.Runtime.InteropServices;

namespace System.Runtime
{
public sealed partial class MemoryFailPoint
{
private static ulong GetTopOfMemory()
{
Interop.Kernel32.SYSTEM_INFO info = new Interop.Kernel32.SYSTEM_INFO();
Interop.Kernel32.GetSystemInfo(out info);
return (ulong)info.lpMaximumApplicationAddress;
}

private static bool CheckForAvailableMemory(out ulong availPageFile, out ulong totalAddressSpaceFree)
{
bool r;
Interop.Kernel32.MEMORYSTATUSEX memory = new Interop.Kernel32.MEMORYSTATUSEX();
r = Interop.Kernel32.GlobalMemoryStatusEx(ref memory);
if (!r)
throw Win32Marshal.GetExceptionForLastWin32Error();
availPageFile = memory.availPageFile;
totalAddressSpaceFree = memory.availVirtual;
// Console.WriteLine($"Memory gate: Mem load: {memory.memoryLoad}% Available memory (physical + page file): {(memory.availPageFile >> 20)} MB Total free address space: {memory.availVirtual >> 20} MB GC Heap: {(GC.GetTotalMemory(true) >> 20)} MB");
return true;
}

// Based on the shouldThrow parameter, this will throw an exception, or
// returns whether there is enough space. In all cases, we update
// our last known free address space, hopefully avoiding needing to
// probe again.
private static unsafe bool CheckForFreeAddressSpace(ulong size, bool shouldThrow)
{
// Start walking the address space at 0. VirtualAlloc may wrap
// around the address space. We don't need to find the exact
// pages that VirtualAlloc would return - we just need to
// know whether VirtualAlloc could succeed.
ulong freeSpaceAfterGCHeap = MemFreeAfterAddress(null, size);

// Console.WriteLine($"MemoryFailPoint: Checked for free VA space. Found enough? {(freeSpaceAfterGCHeap >= size)} Asked for: {size} Found: {freeSpaceAfterGCHeap}");

// We may set these without taking a lock - I don't believe
// this will hurt, as long as we never increment this number in
// the Dispose method. If we do an extra bit of checking every
// once in a while, but we avoid taking a lock, we may win.
LastKnownFreeAddressSpace = (long)freeSpaceAfterGCHeap;
LastTimeCheckingAddressSpace = Environment.TickCount;

if (freeSpaceAfterGCHeap < size && shouldThrow)
throw new InsufficientMemoryException(SR.InsufficientMemory_MemFailPoint_VAFrag);
return freeSpaceAfterGCHeap >= size;
}

// Returns the amount of consecutive free memory available in a block
// of pages. If we didn't have enough address space, we still return
// a positive value < size, to help potentially avoid the overhead of
// this check if we use a MemoryFailPoint with a smaller size next.
private static unsafe ulong MemFreeAfterAddress(void* address, ulong size)
{
if (size >= s_topOfMemory)
return 0;

ulong largestFreeRegion = 0;
Interop.Kernel32.MEMORY_BASIC_INFORMATION memInfo = new Interop.Kernel32.MEMORY_BASIC_INFORMATION();
UIntPtr sizeOfMemInfo = (UIntPtr)sizeof(Interop.Kernel32.MEMORY_BASIC_INFORMATION);

while (((ulong)address) + size < s_topOfMemory)
{
UIntPtr r = Interop.Kernel32.VirtualQuery(address, ref memInfo, sizeOfMemInfo);
if (r == UIntPtr.Zero)
throw Win32Marshal.GetExceptionForLastWin32Error();

ulong regionSize = memInfo.RegionSize.ToUInt64();
if (memInfo.State == Interop.Kernel32.MEM_FREE)
{
if (regionSize >= size)
return regionSize;
else
largestFreeRegion = Math.Max(largestFreeRegion, regionSize);
}
address = (void*)((ulong)address + regionSize);
}
return largestFreeRegion;
}

// Allocate a specified number of bytes, commit them and free them. This should enlarge
// page file if necessary and possible.
private static void GrowPageFileIfNecessaryAndPossible(UIntPtr numBytes)
{
unsafe
{
#if ENABLE_WINRT
void* pMemory = Interop.mincore.VirtualAllocFromApp(null, numBytes, Interop.Kernel32.MEM_COMMIT, Interop.Kernel32.PAGE_READWRITE);
#else
void* pMemory = Interop.Kernel32.VirtualAlloc(null, numBytes, Interop.Kernel32.MEM_COMMIT, Interop.Kernel32.PAGE_READWRITE);
#endif
if (pMemory != null)
{
bool r = Interop.Kernel32.VirtualFree(pMemory, UIntPtr.Zero, Interop.Kernel32.MEM_RELEASE);
if (!r)
throw Win32Marshal.GetExceptionForLastWin32Error();
}
}
}
}
}
Loading