| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // Copyright (c) The Avalonia Project. All rights reserved.
- // Licensed under the MIT license. See licence.md file in the project root for full license information.
- using System;
- using System.Collections.Generic;
- using System.Reflection;
- using System.Resources;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using System.Threading;
- using Avalonia.Platform;
- namespace Avalonia.Shared.PlatformSupport
- {
- internal partial class StandardRuntimePlatform : IRuntimePlatform
- {
- public void PostThreadPoolItem(Action cb) => ThreadPool.UnsafeQueueUserWorkItem(_ => cb(), null);
- public Assembly[] GetLoadedAssemblies() => AppDomain.CurrentDomain.GetAssemblies();
- public IDisposable StartSystemTimer(TimeSpan interval, Action tick)
- {
- return new Timer(_ => tick(), null, interval, interval);
- }
- public string GetStackTrace() => Environment.StackTrace;
- public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(this, size);
-
- class UnmanagedBlob : IUnmanagedBlob
- {
- private readonly StandardRuntimePlatform _plat;
- private IntPtr _address;
- private readonly object _lock = new object();
- #if DEBUG
- private static readonly List<string> Backtraces = new List<string>();
- private static Thread GCThread;
- private readonly string _backtrace;
- private static readonly object _btlock = new object();
- class GCThreadDetector
- {
- ~GCThreadDetector()
- {
- GCThread = Thread.CurrentThread;
- }
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- static void Spawn() => new GCThreadDetector();
-
- static UnmanagedBlob()
- {
- Spawn();
- GC.WaitForPendingFinalizers();
- }
-
- #endif
-
- public UnmanagedBlob(StandardRuntimePlatform plat, int size)
- {
- if (size <= 0)
- throw new ArgumentException("Positive number required", nameof(size));
- _plat = plat;
- _address = plat.Alloc(size);
- GC.AddMemoryPressure(size);
- Size = size;
- #if DEBUG
- _backtrace = Environment.StackTrace;
- lock (_btlock)
- Backtraces.Add(_backtrace);
- #endif
- }
- void DoDispose()
- {
- lock (_lock)
- {
- if (!IsDisposed)
- {
- #if DEBUG
- lock (_btlock)
- Backtraces.Remove(_backtrace);
- #endif
- _plat.Free(_address, Size);
- GC.RemoveMemoryPressure(Size);
- IsDisposed = true;
- _address = IntPtr.Zero;
- Size = 0;
- }
- }
- }
- public void Dispose()
- {
- #if DEBUG
- if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId)
- {
- Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: "
- + Environment.StackTrace
- + "\n\nBlob created by " + _backtrace);
- }
- #endif
- DoDispose();
- GC.SuppressFinalize(this);
- }
- ~UnmanagedBlob()
- {
- #if DEBUG
- Console.Error.WriteLine("Undisposed native blob created by " + _backtrace);
- #endif
- DoDispose();
- }
- public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
- public int Size { get; private set; }
- public bool IsDisposed { get; private set; }
- }
-
-
-
- #if FULLDOTNET || DOTNETCORE
- [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 = GetRuntimeInfo().OperatingSystem == OperatingSystemType.Linux)).Value;
-
- IntPtr Alloc(int size)
- {
- if (UseMmap)
- {
- 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;
- }
- else
- return Marshal.AllocHGlobal(size);
- }
- void Free(IntPtr ptr, int len)
- {
- if (UseMmap)
- {
- if (munmap(ptr, new IntPtr(len)) == -1)
- {
- var errno = Marshal.GetLastWin32Error();
- throw new Exception("Unable to free memory: " + errno);
- }
- }
- else
- Marshal.FreeHGlobal(ptr);
- }
- #else
- IntPtr Alloc(int size) => Marshal.AllocHGlobal(size);
- void Free(IntPtr ptr, int len) => Marshal.FreeHGlobal(ptr);
- #endif
- }
- }
|