From 622a166e4986b8bef8d7ade1e31022bd35476b69 Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Wed, 19 Feb 2025 20:41:11 -0500 Subject: [PATCH] Fix constructor for `NativeHandle` and docs in `Interop.Runtime` (#182) * Update docs for `ArenaNativeAllocator` * Update constructor and docs for `NativeHandle` * Update generate `helloworld-app` bindings --- .../Generated/AssemblyAttributes.g.cs | 2 +- .../helloworld-app/Generated/Runtime.g.cs | 112 +++++++++++++++++- .../Generated/my_c_library.g.cs | 2 +- .../Interop.Runtime/ArenaNativeAllocator.cs | 8 +- .../Interop.Runtime/NativeHandle.cs | 10 +- 5 files changed, 119 insertions(+), 15 deletions(-) diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.g.cs b/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.g.cs index 20972e03..2acb5cf5 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.g.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.g.cs @@ -1,5 +1,5 @@ // -// This code was generated by the following tool on 2025-01-27 02:11:24 GMT-05:00: +// This code was generated by the following tool on 2025-02-19 20:34:32 GMT-05:00: // https://github.com/bottlenoselabs/c2cs (v0.0.0.0) // // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.g.cs b/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.g.cs index e43d053d..4dd8b73d 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.g.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.g.cs @@ -1,5 +1,5 @@ // -// This code was generated by the following tool on 2025-01-27 02:11:24 GMT-05:00: +// This code was generated by the following tool on 2025-02-19 20:34:32 GMT-05:00: // https://github.com/bottlenoselabs/c2cs (v0.0.0.0) // // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. @@ -11,6 +11,7 @@ using System; using System.Globalization; using System.Runtime.InteropServices; +using System.Threading; namespace Interop.Runtime; @@ -578,11 +579,11 @@ public static CString AllocateCString(this INativeAllocator allocator, string st /// An allocator that uses a single block of native memory which can be re-used. /// /// -///

+/// /// The can be useful in native interoperability situations when you need to /// temporarily allocate memory. For example, when calling native functions sometimes memory needs be available /// for one or more calls but is no longer used after. -///

+/// ///
public sealed unsafe class ArenaNativeAllocator : INativeAllocator, IDisposable @@ -614,9 +615,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; } @@ -673,14 +675,112 @@ public void Free(IntPtr pointer) /// Resets to zero and clears the entire underlying block of native memory with zeroes. /// /// - ///

+ /// /// Any pointers returned from before calling must not be used or else /// there is a risk that the pointers point to unexpected bytes of data. - ///

+ /// ///
public void Reset() { +#if NET6_0_OR_GREATER + NativeMemory.Clear((void*)_buffer, (UIntPtr)Used); +#else new Span((void*)_buffer, Used).Clear(); +#endif Used = 0; } } + +/// +/// 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); +} + +/// +/// Represents an object instance that is associated with an unmanaged handle. +/// +public abstract class NativeHandle : Disposable +{ + /// + /// Gets or sets the unmanaged handle associated with the object instance. + /// + /// + /// + /// is when is + /// true. + /// + /// + public IntPtr Handle { get; protected set; } + + /// + /// Initializes a new instance of the class. + /// + /// The native handle. + protected NativeHandle(IntPtr handle) + { + Handle = handle; + } + + /// + protected override void Dispose(bool isDisposing) + { + Handle = IntPtr.Zero; + } +} diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.g.cs b/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.g.cs index 1f2cdc9a..5b47b470 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.g.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.g.cs @@ -1,5 +1,5 @@ // -// This code was generated by the following tool on 2025-01-27 02:11:24 GMT-05:00: +// This code was generated by the following tool on 2025-02-19 20:34:32 GMT-05:00: // https://github.com/bottlenoselabs/c2cs (v0.0.0.0) // // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. diff --git a/src/cs/production/Interop.Runtime/ArenaNativeAllocator.cs b/src/cs/production/Interop.Runtime/ArenaNativeAllocator.cs index f34b5344..dd453a10 100644 --- a/src/cs/production/Interop.Runtime/ArenaNativeAllocator.cs +++ b/src/cs/production/Interop.Runtime/ArenaNativeAllocator.cs @@ -10,11 +10,11 @@ namespace Interop.Runtime; /// An allocator that uses a single block of native memory which can be re-used. /// /// -///

+/// /// The can be useful in native interoperability situations when you need to /// temporarily allocate memory. For example, when calling native functions sometimes memory needs be available /// for one or more calls but is no longer used after. -///

+/// ///
public sealed unsafe class ArenaNativeAllocator : INativeAllocator, IDisposable @@ -106,10 +106,10 @@ public void Free(IntPtr pointer) /// Resets to zero and clears the entire underlying block of native memory with zeroes. /// /// - ///

+ /// /// Any pointers returned from before calling must not be used or else /// there is a risk that the pointers point to unexpected bytes of data. - ///

+ /// ///
public void Reset() { diff --git a/src/cs/production/Interop.Runtime/NativeHandle.cs b/src/cs/production/Interop.Runtime/NativeHandle.cs index 547813bf..ad7bb07f 100644 --- a/src/cs/production/Interop.Runtime/NativeHandle.cs +++ b/src/cs/production/Interop.Runtime/NativeHandle.cs @@ -11,7 +11,7 @@ namespace Interop.Runtime; public abstract class NativeHandle : Disposable { /// - /// Gets the unmanaged handle associated with the object instance. + /// Gets or sets the unmanaged handle associated with the object instance. /// /// /// @@ -19,9 +19,13 @@ public abstract class NativeHandle : Disposable /// true. /// /// - public IntPtr Handle { get; internal set; } + public IntPtr Handle { get; protected set; } - internal NativeHandle(IntPtr handle) + /// + /// Initializes a new instance of the class. + /// + /// The native handle. + protected NativeHandle(IntPtr handle) { Handle = handle; }