diff options
Diffstat (limited to 'lib')
9 files changed, 180 insertions, 39 deletions
diff --git a/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs b/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs index db87357..209ab91 100644 --- a/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs +++ b/lib/Net.Transport.SimpleTCP/src/SocketPipeLineWorker.cs @@ -29,6 +29,7 @@ using System.Threading; using System.Net.Sockets; using System.IO.Pipelines; using System.Threading.Tasks; +using System.Runtime.InteropServices; using VNLib.Utils.Memory; using VNLib.Utils.Memory.Caching; @@ -234,7 +235,7 @@ namespace VNLib.Net.Transport.Tcp //Write segment to socket, and upate written data int written = await sock.SendAsync(reader.Window, SocketFlags.None); - if(written >= reader.WindowSize) + if(written == reader.WindowSize) { //All data was written break; @@ -274,6 +275,7 @@ namespace VNLib.Net.Transport.Tcp private FlushResult _recvFlushRes; + private int _sysSocketBufferSize; private async Task RecvDoWorkAsync(Socket sock, bool initialData) { @@ -284,7 +286,7 @@ namespace VNLib.Net.Transport.Tcp try { //Avoid syscall? - int bufferSize = sock.ReceiveBufferSize; + _sysSocketBufferSize = sock.ReceiveBufferSize; //If initial data was buffered, it needs to be published to the reader if (initialData) @@ -303,7 +305,7 @@ namespace VNLib.Net.Transport.Tcp while (true) { //Get buffer from pipe writer - Memory<byte> buffer = RecvPipe.Writer.GetMemory(bufferSize); + Memory<byte> buffer = RecvPipe.Writer.GetMemory(_sysSocketBufferSize); //Wait for data or error from socket int count = await sock.ReceiveAsync(buffer, SocketFlags.None, _cts.Token); @@ -397,8 +399,10 @@ namespace VNLib.Net.Transport.Tcp SendTimer.Restart(SendTimeoutMs); try { + CopyAndPublishDataOnSendPipe(data); + //Send the segment - ValueTask<FlushResult> result = SendPipe.Writer.WriteAsync(data, cancellation); + ValueTask<FlushResult> result = SendPipe.Writer.FlushAsync(cancellation); //Task completed successfully, so if (result.IsCompleted) @@ -430,8 +434,10 @@ namespace VNLib.Net.Transport.Tcp private ValueTask SendWithoutTimerInternalAsync(ReadOnlyMemory<byte> data, CancellationToken cancellation) { + CopyAndPublishDataOnSendPipe(data); + //Send the segment - ValueTask<FlushResult> result = SendPipe.Writer.WriteAsync(data, cancellation); + ValueTask<FlushResult> result = SendPipe.Writer.FlushAsync(cancellation); //Task completed successfully, so if (result.IsCompleted) @@ -454,6 +460,45 @@ namespace VNLib.Net.Transport.Tcp } } + private void CopyAndPublishDataOnSendPipe(ReadOnlyMemory<byte> src) + { + /* + * Clamp the buffer size to the system socket buffer size. If the + * buffer is larger then, we will need to publish multiple segments + */ + if(src.Length > _sysSocketBufferSize) + { + //Store local src buffer reference to copy to + ref byte srcRef = ref MemoryMarshal.GetReference(src.Span); + + uint written = 0; + while (written < src.Length) + { + int dataToCopy = (int)Math.Min(_sysSocketBufferSize, src.Length - written); + + //Get a new buffer span, and ref + Span<byte> dest = SendPipe.Writer.GetSpan(dataToCopy); + ref byte destRef = ref MemoryMarshal.GetReference(dest); + + //Copy data to the buffer at the new position + MemoryUtil.Memmove(ref srcRef, written, ref destRef, 0, (uint)dataToCopy); + + //Advance the writer by the number of bytes written + SendPipe.Writer.Advance(dataToCopy); + + //Increment the written count + written += (uint)dataToCopy; + } + } + else + { + //Single segment, just copy to the writer + Span<byte> dest = SendPipe.Writer.GetSpan(src.Length); + src.Span.CopyTo(dest); + SendPipe.Writer.Advance(src.Length); + } + } + ValueTask ITransportInterface.SendAsync(ReadOnlyMemory<byte> data, CancellationToken cancellation) { //Use timer if timeout is set, dont otherwise diff --git a/lib/Net.Transport.SimpleTCP/src/VNLib.Net.Transport.SimpleTCP.csproj b/lib/Net.Transport.SimpleTCP/src/VNLib.Net.Transport.SimpleTCP.csproj index bfd9fda..ac3e0a1 100644 --- a/lib/Net.Transport.SimpleTCP/src/VNLib.Net.Transport.SimpleTCP.csproj +++ b/lib/Net.Transport.SimpleTCP/src/VNLib.Net.Transport.SimpleTCP.csproj @@ -32,7 +32,7 @@ <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> - <PackageReference Include="System.IO.Pipelines" Version="7.0.0" /> + <PackageReference Include="System.IO.Pipelines" Version="8.0.0" /> </ItemGroup> <ItemGroup> diff --git a/lib/Plugins.PluginBase/src/VNLib.Plugins.PluginBase.csproj b/lib/Plugins.PluginBase/src/VNLib.Plugins.PluginBase.csproj index b9d671d..c7a8414 100644 --- a/lib/Plugins.PluginBase/src/VNLib.Plugins.PluginBase.csproj +++ b/lib/Plugins.PluginBase/src/VNLib.Plugins.PluginBase.csproj @@ -41,8 +41,8 @@ <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> - <PackageReference Include="Serilog" Version="3.0.1" /> - <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> + <PackageReference Include="Serilog" Version="3.1.1" /> + <PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> </ItemGroup> diff --git a/lib/Utils.Memory/vnlib_mimalloc/build.readme.txt b/lib/Utils.Memory/vnlib_mimalloc/build.readme.txt index e69de29..cd003b6 100644 --- a/lib/Utils.Memory/vnlib_mimalloc/build.readme.txt +++ b/lib/Utils.Memory/vnlib_mimalloc/build.readme.txt @@ -0,0 +1,54 @@ +vnlib_mimmalloc Copyright (C) 2023 Vaughn Nugent + +vnlib_mimmalloc is a wrapper library for Mimalloc by Microsoft that implements the NativeHeapApi +functions, and exports them by default for use as a library. The CMake configuration is setup to produce both +a static and shared library you can link against. The NativeHeapApi.h file is included in the source tree +of the archive this readme is included in. Simply add the header to your project and link against the library. + +The NativHeapApi was designed to consolidate heap based operations into a single interface for the purpose of +.NET interop. The shared library (DLL) that is produced can be loaded into a .NET application that uses my +VNLib.Utils library. + +LICENSE: +You also received a copy of the MIT license for mimalloc by Microsoft, and a GNU license for this library from me. + +INSTALLATION: +For the most up-to-date instructions go to my website here: https://www.vaughnnugent.com/resources/software/articles?tags=docs&search=building+native+heap + +If you cannot view the website, here are the basic instructions that may become outdated: + +PREREQUISITES: +- Taskfile.dev (https://taskfile.dev/#/installation) +- CMake (https://cmake.org/download/) +- MSBuild (Vistual Studio build tools) and the CL.exe compiler-linker (Windows only) +- GNU Make + GCC (Unix only) + +NOTE: +If you have any mimalloc specific CMake options you want to use, when running task, you can pass them as +an the MIMALLOC_CMAKE_ARGS env variable. + +Example: >task MIMALLOC_CMAKE_ARGS="-DMI_SECURE=ON" (enable secure mode for mimalloc) + +See: https://microsoft.github.io/mimalloc/build.html for more information on mimalloc specific CMake options. + +BUILDING: +1. You have already downloaded all the source code to build this library +2. Navigate to directory containing the Taskfile.yaml file in the root +3. Run the default task: > task (yes literally just type "task" and hit enter if you installed Task gobally) + +WINDOWS: +The taskfile should print on screen where the output library file was placed. It will be in the build directory +usually under Debug or Release. + +UNIX: +Navigate to the build directory after the task completes, and both the shared .so and static .a files will be +in the build directory. + +MIMALLOC SPECIFIC NOTES: +Mimalloc does not support cross-thread allocations on a privately head heap, which is paramount for my intented +use case. I have not found a way to make this work, so I have implemented a workaround by exporting only the +shared heap instance. This means that all allocations will be made on the shared heap, and not on a private heap. +Hopefully in the future I can find a way to make this work, but for now understand that if your use cause relied +on security from private heaps, you should avoid using this library. That being said, my libraries do not assume +security features for private heaps only lockless performance. Mimalloc does offer many more security features +that are worth using. diff --git a/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.c b/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.c index a3a2e6b..cb8707f 100644 --- a/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.c +++ b/lib/Utils.Memory/vnlib_mimalloc/vnlib_mimalloc.c @@ -37,9 +37,12 @@ HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flag * things working. * * Always clear serialize flag and set shared heap pointer + * + * Shared heap supports realloc, so set the flag */ flags->CreationFlags &= ~(HEAP_CREATION_SERIALZE_ENABLED); + flags->CreationFlags |= HEAP_CREATION_SUPPORTS_REALLOC; flags->HeapPointer = heapGetSharedHeapHandle(); diff --git a/lib/Utils.Memory/vnlib_rpmalloc/build.readme.txt b/lib/Utils.Memory/vnlib_rpmalloc/build.readme.txt index e69de29..77f2193 100644 --- a/lib/Utils.Memory/vnlib_rpmalloc/build.readme.txt +++ b/lib/Utils.Memory/vnlib_rpmalloc/build.readme.txt @@ -0,0 +1,37 @@ +vnlib_rpmalloc Copyright (C) 2023 Vaughn Nugent + +vnlib_rpmalloc is a wrapper library for rpmalloc by Mattias Jansson that implements the NativeHeapApi +functions, and exports them by default for use as a library. The CMake configuration is setup to produce both +a static and shared library you can link against. The NativeHeapApi.h file is included in the source tree +of the archive this readme is included in. Simply add the header to your project and link against the library. + +The NativHeapApi was designed to consolidate heap based operations into a single interface for the purpose of +.NET interop. The shared library (DLL) that is produced can be loaded into a .NET application that uses +my VNLib.Utils library. + +LICENSE: +You also received a copy of the license for rpmalloc by Mattias Jansson, and a GNU license for this library. + +INSTALLATION: +For the most up-to-date instructions go to my website here: https://www.vaughnnugent.com/resources/software/articles?tags=docs&search=building+native+heap + +If you cannot view the website, here are the basic instructions that may become outdated: + +PREREQUISITES: +- Taskfile.dev (https://taskfile.dev/#/installation) +- CMake (https://cmake.org/download/) +- MSBuild (Vistual Studio build tools) and the CL.exe compiler-linker (Windows only) +- GNU Make + GCC (Unix only) + +BUILDING: +1. You have already downloaded all the source code to build this library +2. Navigate to directory containing the Taskfile.yaml file in the root +3. Run the default task: > task (yes literally just type "task" and hit enter if you installed Task gobally) + +WINDOWS: +The taskfile should print on screen where the output library file was placed. It will be in the build directory +usually under Debug or Release. + +UNIX: +Navigate to the build directory after the task completes, and both the shared .so and static .a files will be +in the build directory. diff --git a/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c index b1faf85..5173643 100644 --- a/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c +++ b/lib/Utils.Memory/vnlib_rpmalloc/vnlib_rpmalloc.c @@ -152,6 +152,9 @@ HEAP_METHOD_EXPORT HeapHandle HEAP_METHOD_CC heapGetSharedHeapHandle(void) HEAP_METHOD_EXPORT ERRNO HEAP_METHOD_CC heapCreate(UnmanagedHeapDescriptor* flags) { + //All heaps support resizing + flags->CreationFlags |= HEAP_CREATION_SUPPORTS_REALLOC; + //Check flags if (flags->CreationFlags & HEAP_CREATION_IS_SHARED) { diff --git a/lib/Utils/src/Memory/MemoryUtil.cs b/lib/Utils/src/Memory/MemoryUtil.cs index 75e2d4c..5d979c9 100644 --- a/lib/Utils/src/Memory/MemoryUtil.cs +++ b/lib/Utils/src/Memory/MemoryUtil.cs @@ -325,10 +325,7 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InitializeBlock<T>(T[] array, uint count) where T: struct { - if(array == null) - { - throw new ArgumentNullException(nameof(array)); - } + ArgumentNullException.ThrowIfNull(array, nameof(array)); //Check bounds CheckBounds(array, 0, count); @@ -392,7 +389,18 @@ namespace VNLib.Utils.Memory /// <typeparam name="T">The structure type</typeparam> /// <param name="structRef">The reference to the allocated structure</param> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ZeroStruct<T>(ref T structRef) where T : unmanaged => InitializeBlock(ref structRef, 1); + public static void ZeroStruct<T>(ref T structRef) where T : unmanaged + { + if (Unsafe.IsNullRef(ref structRef)) + { + throw new ArgumentNullException(nameof(structRef)); + } + + //Get a byte reference to the structure + ref byte byteRef = ref Unsafe.As<T, byte>(ref structRef); + + Unsafe.InitBlockUnaligned(ref byteRef, 0, (uint)sizeof(T)); + } /// <summary> /// Zeroes a block of memory pointing to the structure @@ -730,10 +738,7 @@ namespace VNLib.Utils.Memory /// <exception cref="ArgumentOutOfRangeException"></exception> public static void Copy<T>(ReadOnlySpan<T> source, int sourceOffset, IMemoryHandle<T> dest, nuint destOffset, int count) where T: struct { - if (dest is null) - { - throw new ArgumentNullException(nameof(dest)); - } + ArgumentNullException.ThrowIfNull(dest, nameof(dest)); if (count == 0) { @@ -783,7 +788,7 @@ namespace VNLib.Utils.Memory /// <exception cref="ArgumentOutOfRangeException"></exception> public static void Copy<T>(IMemoryHandle<T> source, nint sourceOffset, Span<T> dest, int destOffset, int count) where T : struct { - _ = source ?? throw new ArgumentNullException(nameof(source)); + ArgumentNullException.ThrowIfNull(source, nameof(source)); //Validate source/dest/count ValidateCopyArgs(sourceOffset, destOffset, count); @@ -840,8 +845,8 @@ namespace VNLib.Utils.Memory /// <exception cref="ArgumentOutOfRangeException"></exception> public static void Copy<T>(IMemoryHandle<T> source, nuint sourceOffset, IMemoryHandle<T> dest, nuint destOffset, nuint count) where T : unmanaged { - _ = source ?? throw new ArgumentNullException(nameof(source)); - _ = dest ?? throw new ArgumentNullException(nameof(dest)); + ArgumentNullException.ThrowIfNull(source, nameof(source)); + ArgumentNullException.ThrowIfNull(dest, nameof(dest)); CheckBounds(source, sourceOffset, count); CheckBounds(dest, destOffset, count); @@ -897,15 +902,8 @@ namespace VNLib.Utils.Memory /// <exception cref="ArgumentOutOfRangeException"></exception> public static void CopyArray<T>(IMemoryHandle<T> source, nuint sourceOffset, T[] dest, nuint destOffset, nuint count) where T : unmanaged { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - if (dest is null) - { - throw new ArgumentNullException(nameof(dest)); - } + ArgumentNullException.ThrowIfNull(source, nameof(source)); + ArgumentNullException.ThrowIfNull(dest, nameof(dest)); if (count == 0) { @@ -951,15 +949,8 @@ namespace VNLib.Utils.Memory /// <exception cref="ArgumentOutOfRangeException"></exception> public static void CopyArray<T>(T[] source, nuint sourceOffset, IMemoryHandle<T> dest, nuint destOffset, nuint count) where T : unmanaged { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - if (dest is null) - { - throw new ArgumentNullException(nameof(dest)); - } + ArgumentNullException.ThrowIfNull(source, nameof(source)); + ArgumentNullException.ThrowIfNull(dest, nameof(dest)); if (count == 0) { @@ -1301,6 +1292,14 @@ namespace VNLib.Utils.Memory } /// <summary> + /// Gets a managed pointer from the supplied handle + /// </summary> + /// <param name="handle">A reference to the handle to get the intpr for</param> + /// <returns>A managed pointer from the handle</returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IntPtr GetIntptr(ref MemoryHandle handle) => new(handle.Pointer); + + /// <summary> /// Rounds the requested byte size up to the nearest page /// number of bytes /// </summary> diff --git a/lib/Utils/tests/VNLib.UtilsTests.csproj b/lib/Utils/tests/VNLib.UtilsTests.csproj index 9053c51..f8cb807 100644 --- a/lib/Utils/tests/VNLib.UtilsTests.csproj +++ b/lib/Utils/tests/VNLib.UtilsTests.csproj @@ -16,7 +16,7 @@ <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /> <PackageReference Include="MSTest.TestAdapter" Version="3.1.1" /> <PackageReference Include="MSTest.TestFramework" Version="3.1.1" /> <PackageReference Include="coverlet.collector" Version="6.0.0"> |