Skip to content

Commit

Permalink
Fix ArenaNativeAllocator bug + add Disposable and NativeHandle (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
lithiumtoast authored Feb 17, 2025
1 parent e497f97 commit 157b894
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 2 deletions.
7 changes: 6 additions & 1 deletion src/cs/production/Interop.Runtime/ArenaNativeAllocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte>((void*)_buffer, Capacity).Clear();
#endif
Capacity = capacity;
}
Expand Down Expand Up @@ -112,7 +113,11 @@ public void Free(IntPtr pointer)
/// </remarks>
public void Reset()
{
#if NET6_0_OR_GREATER
NativeMemory.Clear((void*)_buffer, (UIntPtr)Used);
#else
new Span<byte>((void*)_buffer, Used).Clear();
#endif
Used = 0;
}
}
1 change: 0 additions & 1 deletion src/cs/production/Interop.Runtime/CStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
69 changes: 69 additions & 0 deletions src/cs/production/Interop.Runtime/Disposable.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Represents a object instance that has unmanaged resources that can be free-ed, released, or reset.
/// </summary>
public abstract class Disposable : IDisposable
{
private volatile int _isDisposed;

/// <summary>
/// Gets a value indicating whether the object instance has free-ed, released, or reset unmanaged resources.
/// </summary>
/// <remarks><para><see cref="IsDisposed" /> is thread-safe via atomic operations.</para></remarks>
public bool IsDisposed => _isDisposed == 1;

/// <summary>
/// Performs tasks related to freeing, releasing, or resetting unmanaged resources.
/// </summary>
#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);
}

/// <summary>
/// Finalizes an instance of the <see cref="Disposable" /> class.
/// </summary>
[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);
}

/// <summary>
/// Performs tasks related to freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <param name="isDisposing">
/// <c>true</c> if <see cref="Dispose()" /> was called explicitly. <c>false</c> if
/// <see cref="Dispose()" /> was called implicitly by the garbage collector finalizer.
/// </param>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
protected abstract void Dispose(bool isDisposing);
}
34 changes: 34 additions & 0 deletions src/cs/production/Interop.Runtime/NativeHandle.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Represents an object instance that is associated with an unmanaged handle.
/// </summary>
public abstract class NativeHandle : Disposable
{
/// <summary>
/// Gets the unmanaged handle associated with the object instance.
/// </summary>
/// <remarks>
/// <para>
/// <see cref="Handle" /> is <see cref="IntPtr.Zero" /> when <see cref="Disposable.IsDisposed" /> is
/// <c>true</c>.
/// </para>
/// </remarks>
public IntPtr Handle { get; internal set; }

internal NativeHandle(IntPtr handle)
{
Handle = handle;
}

/// <inheritdoc />
protected override void Dispose(bool isDisposing)
{
Handle = IntPtr.Zero;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 ? ";" : "{}")}
Expand Down
8 changes: 8 additions & 0 deletions src/cs/production/c2cs.Tool/c2cs.Tool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@
<Visible>false</Visible>
<Link>ArenaNativeAllocator.cs</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\Interop.Runtime\Disposable.cs">
<Visible>false</Visible>
<Link>Disposable.cs</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\Interop.Runtime\NativeHandle.cs">
<Visible>false</Visible>
<Link>NativeHandle.cs</Link>
</EmbeddedResource>
<EmbeddedResource Include="appsettings.json" />
</ItemGroup>

Expand Down

0 comments on commit 157b894

Please sign in to comment.