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.Buffers; 6 using System.Diagnostics; 7 using System.Runtime.InteropServices; 8 9 namespace System.Buffers 10 { 11 internal sealed class NativeOwnedMemory : OwnedMemory<byte> 12 { 13 private readonly int _length; 14 private IntPtr _ptr; 15 private int _retainedCount; 16 private bool _disposed; 17 NativeOwnedMemory(int length)18 public NativeOwnedMemory(int length) 19 { 20 _length = length; 21 _ptr = Marshal.AllocHGlobal(length); 22 } 23 ~NativeOwnedMemory()24 ~NativeOwnedMemory() 25 { 26 Debug.WriteLine($"{nameof(NativeOwnedMemory)} being finalized"); 27 Dispose(false); 28 } 29 30 public override bool IsDisposed 31 { 32 get 33 { 34 lock (this) 35 { 36 return _disposed && _retainedCount == 0; 37 } 38 } 39 } 40 41 public override int Length => _length; 42 43 protected override bool IsRetained 44 { 45 get 46 { 47 lock (this) 48 { 49 return _retainedCount > 0; 50 } 51 } 52 } 53 54 public override unsafe Span<byte> Span => new Span<byte>((void*)_ptr, _length); 55 Pin(int offset = 0)56 public override unsafe MemoryHandle Pin(int offset = 0) 57 { 58 if (offset < 0 || offset > _length) throw new ArgumentOutOfRangeException(nameof(offset)); 59 void* pointer = (void*)((byte*)_ptr + offset); 60 return new MemoryHandle(this, pointer); 61 } 62 Release()63 public override bool Release() 64 { 65 lock (this) 66 { 67 if (_retainedCount > 0) 68 { 69 _retainedCount--; 70 if (_retainedCount == 0) 71 { 72 if (_disposed) 73 { 74 Marshal.FreeHGlobal(_ptr); 75 _ptr = IntPtr.Zero; 76 } 77 return true; 78 } 79 } 80 } 81 return false; 82 } 83 Retain()84 public override void Retain() 85 { 86 lock (this) 87 { 88 if (_retainedCount == 0 && _disposed) 89 { 90 throw new Exception(); 91 } 92 _retainedCount++; 93 } 94 } 95 Dispose(bool disposing)96 protected override void Dispose(bool disposing) 97 { 98 lock (this) 99 { 100 _disposed = true; 101 if (_retainedCount == 0) 102 { 103 Marshal.FreeHGlobal(_ptr); 104 _ptr = IntPtr.Zero; 105 } 106 } 107 } 108 TryGetArray(out ArraySegment<byte> arraySegment)109 protected override bool TryGetArray(out ArraySegment<byte> arraySegment) 110 { 111 arraySegment = default(ArraySegment<byte>); 112 return false; 113 } 114 } 115 } 116