diff --git a/src/cs/production/Interop.Runtime/ArenaNativeAllocator.cs b/src/cs/production/Interop.Runtime/ArenaNativeAllocator.cs index 97631d1d..f34b5344 100644 --- a/src/cs/production/Interop.Runtime/ArenaNativeAllocator.cs +++ b/src/cs/production/Interop.Runtime/ArenaNativeAllocator.cs @@ -46,9 +46,10 @@ public ArenaNativeAllocator(int capacity) #if NET6_0_OR_GREATER // malloc - _buffer = (IntPtr)NativeMemory.Alloc((UIntPtr)capacity); + _buffer = (IntPtr)NativeMemory.AllocZeroed((UIntPtr)capacity); #else _buffer = Marshal.AllocHGlobal(capacity); + new Span((void*)_buffer, Capacity).Clear(); #endif Capacity = capacity; } @@ -112,7 +113,11 @@ public void Free(IntPtr pointer) /// public void Reset() { +#if NET6_0_OR_GREATER + NativeMemory.Clear((void*)_buffer, (UIntPtr)Used); +#else new Span((void*)_buffer, Used).Clear(); +#endif Used = 0; } } diff --git a/src/cs/production/Interop.Runtime/CStrings.cs b/src/cs/production/Interop.Runtime/CStrings.cs index 1d707839..4f832779 100644 --- a/src/cs/production/Interop.Runtime/CStrings.cs +++ b/src/cs/production/Interop.Runtime/CStrings.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information. using System; -using System.Runtime.InteropServices; namespace Interop.Runtime; diff --git a/src/cs/production/Interop.Runtime/Disposable.cs b/src/cs/production/Interop.Runtime/Disposable.cs new file mode 100644 index 00000000..c0edceeb --- /dev/null +++ b/src/cs/production/Interop.Runtime/Disposable.cs @@ -0,0 +1,69 @@ +// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved. +// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information. + +using System; +using System.Threading; + +namespace Interop.Runtime; + +/// +/// Represents a object instance that has unmanaged resources that can be free-ed, released, or reset. +/// +public abstract class Disposable : IDisposable +{ + private volatile int _isDisposed; + + /// + /// Gets a value indicating whether the object instance has free-ed, released, or reset unmanaged resources. + /// + /// is thread-safe via atomic operations. + public bool IsDisposed => _isDisposed == 1; + + /// + /// Performs tasks related to freeing, releasing, or resetting unmanaged resources. + /// +#pragma warning disable CA1063 + public void Dispose() +#pragma warning restore CA1063 + { +#pragma warning disable CS0420 // A reference to a volatile field will not be treated as volatile + var isDisposed = Interlocked.CompareExchange(ref _isDisposed, 1, 0); +#pragma warning restore CS0420 // A reference to a volatile field will not be treated as volatile + if (isDisposed == 1) + { + return; + } + + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Finalizes an instance of the class. + /// + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] +#pragma warning disable CA1063 + ~Disposable() +#pragma warning restore CA1063 + { +#pragma warning disable CS0420 // A reference to a volatile field will not be treated as volatile + var isDisposed = Interlocked.CompareExchange(ref _isDisposed, 1, 0); +#pragma warning restore CS0420 // A reference to a volatile field will not be treated as volatile + if (isDisposed == 1) + { + return; + } + + Dispose(false); + } + + /// + /// Performs tasks related to freeing, releasing, or resetting unmanaged resources. + /// + /// + /// true if was called explicitly. false if + /// was called implicitly by the garbage collector finalizer. + /// + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + protected abstract void Dispose(bool isDisposing); +} diff --git a/src/cs/production/Interop.Runtime/NativeHandle.cs b/src/cs/production/Interop.Runtime/NativeHandle.cs new file mode 100644 index 00000000..547813bf --- /dev/null +++ b/src/cs/production/Interop.Runtime/NativeHandle.cs @@ -0,0 +1,34 @@ +// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved. +// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information. + +using System; + +namespace Interop.Runtime; + +/// +/// Represents an object instance that is associated with an unmanaged handle. +/// +public abstract class NativeHandle : Disposable +{ + /// + /// Gets the unmanaged handle associated with the object instance. + /// + /// + /// + /// is when is + /// true. + /// + /// + public IntPtr Handle { get; internal set; } + + internal NativeHandle(IntPtr handle) + { + Handle = handle; + } + + /// + protected override void Dispose(bool isDisposing) + { + Handle = IntPtr.Zero; + } +} diff --git a/src/cs/production/c2cs.Tool/GenerateCSharpCode/CodeGeneratorDocumentInteropRuntime.cs b/src/cs/production/c2cs.Tool/GenerateCSharpCode/CodeGeneratorDocumentInteropRuntime.cs index ce57a1f3..0303d988 100644 --- a/src/cs/production/c2cs.Tool/GenerateCSharpCode/CodeGeneratorDocumentInteropRuntime.cs +++ b/src/cs/production/c2cs.Tool/GenerateCSharpCode/CodeGeneratorDocumentInteropRuntime.cs @@ -28,6 +28,7 @@ public CodeProjectDocument Generate(CodeGeneratorDocumentOptions options) using System; using System.Globalization; using System.Runtime.InteropServices; + using System.Threading; namespace Interop.Runtime{(options.IsEnabledFileScopedNamespace ? ";" : "{}")} diff --git a/src/cs/production/c2cs.Tool/c2cs.Tool.csproj b/src/cs/production/c2cs.Tool/c2cs.Tool.csproj index 32fb6dd9..92468e29 100644 --- a/src/cs/production/c2cs.Tool/c2cs.Tool.csproj +++ b/src/cs/production/c2cs.Tool/c2cs.Tool.csproj @@ -73,6 +73,14 @@ false ArenaNativeAllocator.cs + + false + Disposable.cs + + + false + NativeHandle.cs +