aboutsummaryrefslogtreecommitdiff
path: root/lib/Utils
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-04-26 20:45:18 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2023-04-26 20:45:18 -0400
commit6827ac3c3aebca96b0411d2df8c79454c47a37de (patch)
treea1798527e92029c49f17ea3fa510248a97938b0e /lib/Utils
parentb0df3871f71e9bafdde3808f81984ac871eef2d4 (diff)
Global heap hex flags passing, and unmanaged block initialization via pointer
Diffstat (limited to 'lib/Utils')
-rw-r--r--lib/Utils/README.md4
-rw-r--r--lib/Utils/src/Memory/MemoryUtil.cs55
-rw-r--r--lib/Utils/tests/Memory/MemoryUtilTests.cs25
3 files changed, 72 insertions, 12 deletions
diff --git a/lib/Utils/README.md b/lib/Utils/README.md
index 34e28d5..98abb07 100644
--- a/lib/Utils/README.md
+++ b/lib/Utils/README.md
@@ -17,7 +17,7 @@ namespaces
Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file.
### Recommended 3rd Party Libs
-This library does not *require* any direct dependencies, however there are some optional ones that are desired for higher performance code. This library does not, modify, contribute, or affect the functionality of any of the 3rd party libraries recommended below.
+This library does not require any direct dependencies, however there are some optional ones that are recommended for higher performance. This library does not, modify, contribute, or affect the functionality of any of the 3rd party libraries recommended below.
[**RPMalloc**](https://github.com/mjansson/rpmalloc) By Mattias Jansson - VNlib.Utils.Memory (and sub-classes) may load and bind function calls to this native library determined by environment variables. To use RPMalloc as the default unmanaged allocator simply add the dynamic library to the native lib search path, such as in the executable directory, and set the allocator environment variable as instructed below. I maintain a compatible Windows x64 [dll library](../WinRpMalloc/README.md) on my website and in this repository, that conforms to the [NativeHeap](../NativeHeapApi/README.md) api required for runtime loading.
@@ -47,6 +47,8 @@ Most VNLib libraries use the Shared heap for performance reasons, and in some ca
### Runtime allocator selection
Setting the `VNLIB_SHARED_HEAP_FILE_PATH` environment variable will instruct the `InitializeNewHeapForProcess` method to load the native heap library at the given path, it may be an absolute path to the DLL file or a dll file name in a "safe" directory. It must conform to the NativeHeapApi, otherwise loading will fail. Understand that loading is deferred to the first access of the `MemoryUtil.Shared` property (this is subject to change) so don't be confused when seeing deferred debugging messages instead of a type initialization failure. This is also done to avoid Loader Lock contention issues, because we can.
+You may pass a hex encoded raw flags to the `heapCreate` method via the `UnmanagedHeapDescriptor.FLags` field globally, by setting the `VNLIB_SHARED_HEAP_RAW_FLAGS` environment variable.
+
#### MemoryUtil fallbacks
If you don't want to use a custom heap implementation, the library has safe fallbacks for all platforms. On Windows the PrivateHeap api is used by default. The shared heap, again, prefers performance and will use the process heap returned from `GetProcessHeap()`, instead of creating a private heap that requires synchronization penalties. On all other platforms the fallback will be the .NET NativeMemory allocator, which is cross platform, but does **not** actually implement a "private" heap. So that means on non-Windows platforms unless you select your own heap, isolation is not an option.
diff --git a/lib/Utils/src/Memory/MemoryUtil.cs b/lib/Utils/src/Memory/MemoryUtil.cs
index 7f96c4a..e802360 100644
--- a/lib/Utils/src/Memory/MemoryUtil.cs
+++ b/lib/Utils/src/Memory/MemoryUtil.cs
@@ -27,6 +27,7 @@ using System.Buffers;
using System.Security;
using System.Threading;
using System.Diagnostics;
+using System.Globalization;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
@@ -61,6 +62,12 @@ namespace VNLib.Utils.Memory
public const string SHARED_HEAP_ENABLE_DIAGNOISTICS_ENV = "VNLIB_SHARED_HEAP_DIAGNOSTICS";
/// <summary>
+ /// The environment variable name used to specify the raw flags to pass to the shared heap
+ /// creation method
+ /// </summary>
+ public const string SHARED_HEAP_RAW_FLAGS = "VNLIB_SHARED_HEAP_RAW_FLAGS";
+
+ /// <summary>
/// Initial shared heap size (bytes)
/// </summary>
public const nuint SHARED_HEAP_INIT_SIZE = 20971520;
@@ -144,16 +151,17 @@ namespace VNLib.Utils.Memory
//Get environment varable
string? heapDllPath = Environment.GetEnvironmentVariable(SHARED_HEAP_FILE_PATH);
+ string? rawFlagsEnv = Environment.GetEnvironmentVariable(SHARED_HEAP_RAW_FLAGS);
//Default flags
HeapCreation cFlags = HeapCreation.UseSynchronization;
/*
- * We need to set the shared flag and the synchronziation flag.
- *
- * The heap impl may reset the synchronziation flag if it does not
- * need serialziation
- */
+ * We need to set the shared flag and the synchronziation flag.
+ *
+ * The heap impl may reset the synchronziation flag if it does not
+ * need serialziation
+ */
cFlags |= isShared ? HeapCreation.IsSharedHeap : HeapCreation.None;
IUnmangedHeap heap;
@@ -161,8 +169,16 @@ namespace VNLib.Utils.Memory
//Check for heap api dll
if (!string.IsNullOrWhiteSpace(heapDllPath))
{
+ ERRNO rawFlags = 0;
+
+ //Try to parse the raw flags to pass to the heap
+ if (nint.TryParse(rawFlagsEnv, NumberStyles.HexNumber, null, out nint result))
+ {
+ rawFlags = new(result);
+ }
+
//Attempt to load the heap
- heap = NativeHeap.LoadHeap(heapDllPath, DllImportSearchPath.SafeDirectories, cFlags, 0);
+ heap = NativeHeap.LoadHeap(heapDllPath, DllImportSearchPath.SafeDirectories, cFlags, rawFlags);
}
//No user heap was specified, use fallback
else if (IsWindows)
@@ -265,6 +281,27 @@ namespace VNLib.Utils.Memory
public static void InitializeBlock<T>(Memory<T> block) where T : unmanaged => UnsafeZeroMemory<T>(block);
/// <summary>
+ /// Zeroes a block of memory of the given unmanaged type
+ /// </summary>
+ /// <typeparam name="T">The unmanaged type to zero</typeparam>
+ /// <param name="block">A pointer to the block of memory to zero</param>
+ /// <param name="itemCount">The number of elements in the block to zero</param>
+ [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
+ public static void InitializeBlock<T>(T* block, int itemCount) where T : unmanaged
+ {
+ if (itemCount == 0)
+ {
+ return;
+ }
+
+ //Get the size of the structure
+ int size = Unsafe.SizeOf<T>();
+
+ //Zero block
+ Unsafe.InitBlock(block, 0, (uint)(size * itemCount));
+ }
+
+ /// <summary>
/// Zeroes a block of memory pointing to the structure
/// </summary>
/// <typeparam name="T">The structure type</typeparam>
@@ -276,7 +313,7 @@ namespace VNLib.Utils.Memory
//Zero block
Unsafe.InitBlock(block.ToPointer(), 0, (uint)size);
}
-
+
/// <summary>
/// Zeroes a block of memory pointing to the structure
/// </summary>
@@ -289,7 +326,7 @@ namespace VNLib.Utils.Memory
//Zero block
Unsafe.InitBlock(structPtr, 0, (uint)size);
}
-
+
/// <summary>
/// Zeroes a block of memory pointing to the structure
/// </summary>
@@ -302,7 +339,7 @@ namespace VNLib.Utils.Memory
//Zero block
Unsafe.InitBlock(structPtr, 0, (uint)size);
}
-
+
#endregion
#region Copy
diff --git a/lib/Utils/tests/Memory/MemoryUtilTests.cs b/lib/Utils/tests/Memory/MemoryUtilTests.cs
index 473281f..85d3a60 100644
--- a/lib/Utils/tests/Memory/MemoryUtilTests.cs
+++ b/lib/Utils/tests/Memory/MemoryUtilTests.cs
@@ -1,5 +1,4 @@
-
-using System;
+using System;
using System.Buffers;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
@@ -110,6 +109,28 @@ namespace VNLib.Utils.Memory.Tests
Assert.IsTrue(AllZero(buffer.Span));
}
+ [TestMethod()]
+ public unsafe void InitializeBlockPointerTest()
+ {
+ const int blockSize = 64;
+
+ //We want to zero a block of memory by its pointer
+
+ //Heap alloc a block of memory
+ byte* ptr = (byte*)MemoryUtil.Shared.Alloc(blockSize, sizeof(byte), false);
+
+ //Fill with random data
+ RandomNumberGenerator.Fill(new Span<byte>(ptr, blockSize));
+
+ //Make sure the block is not all zero
+ Assert.IsFalse(AllZero(new ReadOnlySpan<byte>(ptr, blockSize)));
+
+ //Zero the block
+ MemoryUtil.InitializeBlock(ptr, blockSize);
+
+ //Confrim all zero
+ Assert.IsTrue(AllZero(new ReadOnlySpan<byte>(ptr, blockSize)));
+ }
[TestMethod()]
public unsafe void UnsafeAllocTest()