Browse Source

Bring back mmap for linux as discussed

pull/8183/head
Max Katz 4 years ago
parent
commit
51789f56a6
  1. 50
      src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs

50
src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs

@ -40,7 +40,7 @@ internal class UnmanagedBlob : IUnmanagedBlob
{
if (size <= 0)
throw new ArgumentException("Positive number required", nameof(size));
_address = Marshal.AllocHGlobal(size);
_address = Alloc(size);
GC.AddMemoryPressure(size);
Size = size;
}
@ -66,7 +66,7 @@ internal class UnmanagedBlob : IUnmanagedBlob
lock (_btlock)
Backtraces.Remove(_backtrace);
#endif
Marshal.FreeHGlobal(_address);
Free(_address, Size);
GC.RemoveMemoryPressure(Size);
IsDisposed = true;
_address = IntPtr.Zero;
@ -106,4 +106,50 @@ internal class UnmanagedBlob : IUnmanagedBlob
public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
public int Size { get; private set; }
public bool IsDisposed { get; private set; }
[DllImport("libc", SetLastError = true)]
private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset);
[DllImport("libc", SetLastError = true)]
private static extern int munmap(IntPtr addr, IntPtr length);
[DllImport("libc", SetLastError = true)]
private static extern long sysconf(int name);
private bool? _useMmap;
private bool UseMmap
=> _useMmap ?? ((_useMmap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)).Value);
// Could be replaced with https://github.com/dotnet/runtime/issues/40892 when it will be available.
private IntPtr Alloc(int size)
{
if (!UseMmap)
{
return Marshal.AllocHGlobal(size);
}
else
{
var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero);
if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to allocate memory: " + errno);
}
return rv;
}
}
private void Free(IntPtr ptr, int len)
{
if (!UseMmap)
{
Marshal.FreeHGlobal(ptr);
}
else
{
if (munmap(ptr, new IntPtr(len)) == -1)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to free memory: " + errno);
}
}
}
}

Loading…
Cancel
Save