aboutsummaryrefslogtreecommitdiff
path: root/lib/Utils
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-03-04 23:41:23 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-03-04 23:41:23 -0500
commitb78036ed9a1030d619b8f9de4dceabbfaa07861f (patch)
treeec6e9f9eb6168ad40d5fd2fc18e373e502a64000 /lib/Utils
parent330ed1688b01d9022bdcf1a5edbb29d33b5e5464 (diff)
Prefer Monitor performance to SemaphoreSlim for private heaps
Diffstat (limited to 'lib/Utils')
-rw-r--r--lib/Utils/src/Memory/RpMallocPrivateHeap.cs4
-rw-r--r--lib/Utils/src/Memory/UnmanagedHeapBase.cs69
-rw-r--r--lib/Utils/src/Memory/Win32PrivateHeap.cs32
-rw-r--r--lib/Utils/tests/ERRNOTest.cs9
4 files changed, 58 insertions, 56 deletions
diff --git a/lib/Utils/src/Memory/RpMallocPrivateHeap.cs b/lib/Utils/src/Memory/RpMallocPrivateHeap.cs
index 0af91a0..323f228 100644
--- a/lib/Utils/src/Memory/RpMallocPrivateHeap.cs
+++ b/lib/Utils/src/Memory/RpMallocPrivateHeap.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -251,7 +251,7 @@ namespace VNLib.Utils.Memory
//Destroy the heap
rpmalloc_heap_release(handle);
//Release base
- return base.ReleaseHandle();
+ return true;
}
///<inheritdoc/>
diff --git a/lib/Utils/src/Memory/UnmanagedHeapBase.cs b/lib/Utils/src/Memory/UnmanagedHeapBase.cs
index 1f7dc7f..4f5084a 100644
--- a/lib/Utils/src/Memory/UnmanagedHeapBase.cs
+++ b/lib/Utils/src/Memory/UnmanagedHeapBase.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -23,7 +23,6 @@
*/
using System;
-using System.Threading;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
@@ -41,7 +40,7 @@ namespace VNLib.Utils.Memory
/// <summary>
/// The heap synchronization handle
/// </summary>
- protected readonly SemaphoreSlim HeapLock;
+ protected readonly object HeapLock;
/// <summary>
/// The global heap zero flag
@@ -55,7 +54,7 @@ namespace VNLib.Utils.Memory
/// <param name="ownsHandle">A flag that indicates if the handle is owned by the instance</param>
protected UnmanagedHeapBase(bool globalZero, bool ownsHandle) : base(ownsHandle)
{
- HeapLock = new(1, 1);
+ HeapLock = new();
GlobalZero = globalZero;
}
@@ -68,21 +67,25 @@ namespace VNLib.Utils.Memory
//Force zero if global flag is set
zero |= GlobalZero;
bool handleCountIncremented = false;
+
//Increment handle count to prevent premature release
DangerousAddRef(ref handleCountIncremented);
+
//Failed to increment ref count, class has been disposed
if (!handleCountIncremented)
{
throw new ObjectDisposedException("The handle has been released");
}
+
try
{
- //wait for lock
- HeapLock.Wait();
- //Alloc block
- LPVOID block = AllocBlock(elements, size, zero);
- //release lock
- HeapLock.Release();
+ LPVOID block;
+ //Enter lock
+ lock(HeapLock)
+ {
+ //Alloc block
+ block = AllocBlock(elements, size, zero);
+ }
//Check if block was allocated
return block != IntPtr.Zero ? block : throw new NativeMemoryOutOfMemoryException("Failed to allocate the requested block");
}
@@ -99,18 +102,22 @@ namespace VNLib.Utils.Memory
public bool Free(ref LPVOID block)
{
bool result;
+
//If disposed, set the block handle to zero and exit to avoid raising exceptions during finalization
if (IsClosed || IsInvalid)
{
block = IntPtr.Zero;
return true;
}
+
//wait for lock
- HeapLock.Wait();
- //Free block
- result = FreeBlock(block);
- //Release lock before releasing handle
- HeapLock.Release();
+ lock (HeapLock)
+ {
+ //Free block
+ result = FreeBlock(block);
+ //Release lock before releasing handle
+ }
+
//Decrement handle count
DangerousRelease();
//set block to invalid
@@ -123,33 +130,29 @@ namespace VNLib.Utils.Memory
///<exception cref="ObjectDisposedException"></exception>
public void Resize(ref LPVOID block, nuint elements, nuint size, bool zero)
{
- //wait for lock
- HeapLock.Wait();
- /*
- * Realloc may return a null pointer if allocation fails
- * so check the results and only assign the block pointer
- * if the result is valid. Otherwise pointer block should
- * be left untouched
- */
- LPVOID newBlock = ReAllocBlock(block, elements, size, zero);
- //release lock
- HeapLock.Release();
+ LPVOID newBlock;
+
+ lock (HeapLock)
+ {
+ /*
+ * Realloc may return a null pointer if allocation fails
+ * so check the results and only assign the block pointer
+ * if the result is valid. Otherwise pointer block should
+ * be left untouched
+ */
+ newBlock = ReAllocBlock(block, elements, size, zero);
+ }
+
//Check block
if (newBlock == IntPtr.Zero)
{
throw new NativeMemoryOutOfMemoryException("The memory block could not be resized");
}
+
//Set the new block
block = newBlock;
}
- ///<inheritdoc/>
- protected override bool ReleaseHandle()
- {
- HeapLock.Dispose();
- return true;
- }
-
/// <summary>
/// Allocates a block of memory from the heap
/// </summary>
diff --git a/lib/Utils/src/Memory/Win32PrivateHeap.cs b/lib/Utils/src/Memory/Win32PrivateHeap.cs
index bdf22f9..9911195 100644
--- a/lib/Utils/src/Memory/Win32PrivateHeap.cs
+++ b/lib/Utils/src/Memory/Win32PrivateHeap.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -26,10 +26,12 @@ using System;
using System.Diagnostics;
using System.Runtime.Versioning;
using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
using DWORD = System.Int64;
using LPVOID = System.IntPtr;
+
namespace VNLib.Utils.Memory
{
///<summary>
@@ -136,11 +138,11 @@ namespace VNLib.Utils.Memory
{
bool result;
//Lock the heap before validating
- HeapLock.Wait();
- //validate the block on the current heap
- result = HeapValidate(handle, HEAP_NO_FLAGS, block);
- //Unlock the heap
- HeapLock.Release();
+ lock (HeapLock)
+ {
+ //validate the block on the current heap
+ result = HeapValidate(handle, HEAP_NO_FLAGS, block);
+ }
return result;
}
@@ -153,12 +155,13 @@ namespace VNLib.Utils.Memory
public bool Validate()
{
bool result;
+
//Lock the heap before validating
- HeapLock.Wait();
- //validate the entire heap
- result = HeapValidate(handle, HEAP_NO_FLAGS, IntPtr.Zero);
- //Unlock the heap
- HeapLock.Release();
+ lock (HeapLock)
+ {
+ //validate the entire heap
+ result = HeapValidate(handle, HEAP_NO_FLAGS, IntPtr.Zero);
+ }
return result;
}
@@ -168,9 +171,10 @@ namespace VNLib.Utils.Memory
#if TRACE
Trace.WriteLine($"Win32 private heap {handle:x} destroyed");
#endif
- return HeapDestroy(handle) && base.ReleaseHandle();
+ return HeapDestroy(handle);
}
///<inheritdoc/>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override sealed LPVOID AllocBlock(nuint elements, nuint size, bool zero)
{
nuint bytes = checked(elements * size);
@@ -178,9 +182,11 @@ namespace VNLib.Utils.Memory
return HeapAlloc(handle, zero ? HEAP_ZERO_MEMORY : HEAP_NO_FLAGS, bytes);
}
///<inheritdoc/>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override sealed bool FreeBlock(LPVOID block) => HeapFree(handle, HEAP_NO_FLAGS, block);
-
+
///<inheritdoc/>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override sealed LPVOID ReAllocBlock(LPVOID block, nuint elements, nuint size, bool zero)
{
nuint bytes = checked(elements * size);
diff --git a/lib/Utils/tests/ERRNOTest.cs b/lib/Utils/tests/ERRNOTest.cs
index bd14b50..c8a9e61 100644
--- a/lib/Utils/tests/ERRNOTest.cs
+++ b/lib/Utils/tests/ERRNOTest.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.UtilsTests
@@ -22,16 +22,9 @@
* along with VNLib.UtilsTests. If not, see http://www.gnu.org/licenses/.
*/
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using VNLib.Utils;
-
namespace VNLib.Utils.Tests
{
[TestClass]