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