From 18505bb7dc0ea03ed714e37c9bc60f821bf40424 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:10:02 +0300 Subject: [PATCH 1/3] Initial commit with task details for issue #11 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/linksplatform/Memory/issues/11 --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..58d8716 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/linksplatform/Memory/issues/11 +Your prepared branch: issue-11-fbe64687 +Your prepared working directory: /tmp/gh-issue-solver-1757844600053 + +Proceed. \ No newline at end of file From fe255536ef2d44505e274b180f209738c2a1edaa Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:17:48 +0300 Subject: [PATCH 2/3] Add VirtualResizableDirectMemory class using virtual memory API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements cross-platform virtual memory allocation for resizable direct memory: - Uses VirtualAlloc/VirtualFree on Windows - Uses mmap/munmap on Unix-like systems (Linux, macOS) - Optimizes Linux resizing with mremap when available - Includes comprehensive unit tests covering allocation, resizing, and data preservation - Updates version to 0.5.0 and package metadata Resolves issue #11 requesting virtual memory API implementation. πŸ€– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../VirtualResizableDirectMemoryTests.cs | 103 +++++++++ csharp/Platform.Memory/Platform.Memory.csproj | 6 +- .../VirtualResizableDirectMemory.cs | 203 ++++++++++++++++++ 3 files changed, 309 insertions(+), 3 deletions(-) create mode 100644 csharp/Platform.Memory.Tests/VirtualResizableDirectMemoryTests.cs create mode 100644 csharp/Platform.Memory/VirtualResizableDirectMemory.cs diff --git a/csharp/Platform.Memory.Tests/VirtualResizableDirectMemoryTests.cs b/csharp/Platform.Memory.Tests/VirtualResizableDirectMemoryTests.cs new file mode 100644 index 0000000..a3fa62d --- /dev/null +++ b/csharp/Platform.Memory.Tests/VirtualResizableDirectMemoryTests.cs @@ -0,0 +1,103 @@ +using System; +using Xunit; + +namespace Platform.Memory.Tests +{ + public unsafe class VirtualResizableDirectMemoryTests + { + [Fact] + public void CorrectMemoryAllocationTest() + { + using var virtualMemory = new VirtualResizableDirectMemory(); + Assert.True(virtualMemory.Pointer != IntPtr.Zero); + Assert.True(virtualMemory.ReservedCapacity >= VirtualResizableDirectMemory.MinimumCapacity); + Assert.Equal(0, virtualMemory.UsedCapacity); + } + + [Fact] + public void CorrectMemoryReallocationTest() + { + using var virtualMemory = new VirtualResizableDirectMemory(); + var value1 = GetLastByte(virtualMemory); + virtualMemory.ReservedCapacity *= 2; + var value2 = GetLastByte(virtualMemory); + Assert.Equal(value1, value2); + Assert.Equal(0, value1); + } + + [Fact] + public void MemoryZeroingTest() + { + using var virtualMemory = new VirtualResizableDirectMemory(8192); + var pointer = (byte*)virtualMemory.Pointer; + + // Check that initial memory is zeroed + for (int i = 0; i < 8192; i++) + { + Assert.Equal(0, pointer[i]); + } + } + + [Fact] + public void MemoryResizePreservesDataTest() + { + using var virtualMemory = new VirtualResizableDirectMemory(4096); + var pointer = (byte*)virtualMemory.Pointer; + + // Write test pattern + for (int i = 0; i < 1024; i++) + { + pointer[i] = (byte)(i % 256); + } + + // Resize to larger capacity + virtualMemory.ReservedCapacity = 8192; + pointer = (byte*)virtualMemory.Pointer; + + // Verify data is preserved + for (int i = 0; i < 1024; i++) + { + Assert.Equal((byte)(i % 256), pointer[i]); + } + + // Verify new memory is zeroed + for (int i = 4096; i < 8192; i++) + { + Assert.Equal(0, pointer[i]); + } + } + + [Fact] + public void UsedCapacitySetTest() + { + using var virtualMemory = new VirtualResizableDirectMemory(4096); + Assert.Equal(0, virtualMemory.UsedCapacity); + + virtualMemory.UsedCapacity = 2048; + Assert.Equal(2048, virtualMemory.UsedCapacity); + + virtualMemory.UsedCapacity = 4096; + Assert.Equal(4096, virtualMemory.UsedCapacity); + } + + [Fact] + public void InitialCapacityTest() + { + using var virtualMemory1 = new VirtualResizableDirectMemory(); + Assert.Equal(VirtualResizableDirectMemory.MinimumCapacity, virtualMemory1.ReservedCapacity); + + using var virtualMemory2 = new VirtualResizableDirectMemory(8192); + Assert.Equal(8192, virtualMemory2.ReservedCapacity); + + // Test minimum capacity enforcement + using var virtualMemory3 = new VirtualResizableDirectMemory(100); + Assert.Equal(VirtualResizableDirectMemory.MinimumCapacity, virtualMemory3.ReservedCapacity); + } + + private static byte GetLastByte(VirtualResizableDirectMemory virtualMemory) + { + var pointer = (void*)virtualMemory.Pointer; + return *((byte*)pointer + virtualMemory.ReservedCapacity - 1); + } + } +} \ No newline at end of file diff --git a/csharp/Platform.Memory/Platform.Memory.csproj b/csharp/Platform.Memory/Platform.Memory.csproj index 6363b22..7ae5470 100644 --- a/csharp/Platform.Memory/Platform.Memory.csproj +++ b/csharp/Platform.Memory/Platform.Memory.csproj @@ -4,13 +4,13 @@ LinksPlatform's Platform.Memory Class Library Konstantin Diachenko Platform.Memory - 0.4.1 + 0.5.0 Konstantin Diachenko net8 true Platform.Memory Platform.Memory - LinksPlatform;Memory;ArrayMemory;DirectMemoryAsArrayMemoryAdapter;FileArrayMemory;FileMappedResizableDirectMemory;HeapResizableDirectMemory;IArrayMemory;IDirectMemory;IMemory;IResizableDirectMemory;ResizableDirectMemoryBase;TemporaryFileMappedResizableDirectMemory;MemoryMappedFiles + LinksPlatform;Memory;ArrayMemory;DirectMemoryAsArrayMemoryAdapter;FileArrayMemory;FileMappedResizableDirectMemory;HeapResizableDirectMemory;VirtualResizableDirectMemory;IArrayMemory;IDirectMemory;IMemory;IResizableDirectMemory;ResizableDirectMemoryBase;TemporaryFileMappedResizableDirectMemory;MemoryMappedFiles https://raw.githubusercontent.com/linksplatform/Documentation/18469f4d033ee9a5b7b84caab9c585acab2ac519/doc/Avatar-rainbow-icon-64x64.png https://linksplatform.github.io/Memory Unlicense @@ -24,7 +24,7 @@ true snupkg latest - Update target framework from net7 to net8. + Add VirtualResizableDirectMemory class using virtual memory API for cross-platform memory allocation. enable diff --git a/csharp/Platform.Memory/VirtualResizableDirectMemory.cs b/csharp/Platform.Memory/VirtualResizableDirectMemory.cs new file mode 100644 index 0000000..94ffb79 --- /dev/null +++ b/csharp/Platform.Memory/VirtualResizableDirectMemory.cs @@ -0,0 +1,203 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Platform.Unsafe; + +namespace Platform.Memory +{ + /// + /// Represents a memory block allocated using virtual memory API. + /// ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΠ΅Ρ‚ Π±Π»ΠΎΠΊ памяти, Π²Ρ‹Π΄Π΅Π»Π΅Π½Π½Ρ‹ΠΉ с использованиСм API Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠΉ памяти. + /// + public unsafe class VirtualResizableDirectMemory : ResizableDirectMemoryBase + { + #region Native API Constants + + private const uint MEM_COMMIT = 0x1000; + private const uint MEM_RESERVE = 0x2000; + private const uint MEM_RELEASE = 0x8000; + private const uint PAGE_READWRITE = 0x04; + + private const int PROT_READ = 0x1; + private const int PROT_WRITE = 0x2; + private const int MAP_PRIVATE = 0x02; + private const int MAP_ANONYMOUS = 0x20; + private const int MAP_FAILED = -1; + + #endregion + + #region Native API Declarations + + // Windows Virtual Memory API + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr VirtualAlloc(IntPtr lpAddress, nuint dwSize, uint flAllocationType, uint flProtect); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool VirtualFree(IntPtr lpAddress, nuint dwSize, uint dwFreeType); + + // Unix/Linux/macOS Memory Mapping API + [DllImport("libc", SetLastError = true)] + private static extern IntPtr mmap(IntPtr addr, nuint length, int prot, int flags, int fd, nint offset); + + [DllImport("libc", SetLastError = true)] + private static extern int munmap(IntPtr addr, nuint length); + + // Linux-specific mremap (not available on macOS) + [DllImport("libc", SetLastError = true)] + private static extern IntPtr mremap(IntPtr old_address, nuint old_size, nuint new_size, int flags); + + private const int MREMAP_MAYMOVE = 1; + + #endregion + + #region Fields + + private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + private static readonly bool IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + private static readonly bool IsMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + + private long _allocatedSize; + + #endregion + + #region DisposableBase Properties + + /// + protected override string ObjectName + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => $"Virtual memory block at {Pointer} address."; + } + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр класса . + /// + /// Minimum memory size in bytes.ΠœΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€ памяти Π² Π±Π°ΠΉΡ‚Π°Ρ…. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public VirtualResizableDirectMemory(long minimumReservedCapacity) + { + if (minimumReservedCapacity < MinimumCapacity) + { + minimumReservedCapacity = MinimumCapacity; + } + ReservedCapacity = minimumReservedCapacity; + UsedCapacity = 0; + } + + /// + /// Initializes a new instance of the class. + /// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ экзСмпляр класса . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public VirtualResizableDirectMemory() : this(MinimumCapacity) { } + + #endregion + + #region ResizableDirectMemoryBase Methods + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void DisposePointer(IntPtr pointer, long usedCapacity) + { + if (IsWindows) + { + if (!VirtualFree(pointer, 0, MEM_RELEASE)) + { + throw new InvalidOperationException($"Failed to free virtual memory at {pointer}. Error: {Marshal.GetLastWin32Error()}"); + } + } + else + { + if (munmap(pointer, (nuint)_allocatedSize) != 0) + { + throw new InvalidOperationException($"Failed to unmap virtual memory at {pointer}. Error: {Marshal.GetLastPInvokeError()}"); + } + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void OnReservedCapacityChanged(long oldReservedCapacity, long newReservedCapacity) + { + if (Pointer == IntPtr.Zero) + { + // Initial allocation + Pointer = AllocateVirtualMemory(newReservedCapacity); + _allocatedSize = newReservedCapacity; + MemoryBlock.Zero((void*)Pointer, newReservedCapacity); + } + else + { + // Resize existing allocation + if (IsLinux && oldReservedCapacity < newReservedCapacity) + { + // Try to use mremap on Linux for efficient resizing + try + { + var remappedPointer = mremap(Pointer, (nuint)oldReservedCapacity, (nuint)newReservedCapacity, MREMAP_MAYMOVE); + if (remappedPointer != new IntPtr(MAP_FAILED)) + { + Pointer = remappedPointer; + _allocatedSize = newReservedCapacity; + // Zero the new memory region + var pointer = (byte*)Pointer + oldReservedCapacity; + MemoryBlock.Zero(pointer, newReservedCapacity - oldReservedCapacity); + return; + } + } + catch + { + // Fall back to manual allocation and copy + } + } + + // Manual resize: allocate new, copy old, free old + var newPointer = AllocateVirtualMemory(newReservedCapacity); + var copySize = Math.Min(oldReservedCapacity, newReservedCapacity); + Buffer.MemoryCopy((void*)Pointer, (void*)newPointer, newReservedCapacity, copySize); + + // Zero the additional memory if growing + if (newReservedCapacity > oldReservedCapacity) + { + var pointer = (byte*)newPointer + oldReservedCapacity; + MemoryBlock.Zero(pointer, newReservedCapacity - oldReservedCapacity); + } + + DisposePointer(Pointer, oldReservedCapacity); + Pointer = newPointer; + _allocatedSize = newReservedCapacity; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static IntPtr AllocateVirtualMemory(long size) + { + if (IsWindows) + { + var pointer = VirtualAlloc(IntPtr.Zero, (nuint)size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (pointer == IntPtr.Zero) + { + throw new OutOfMemoryException($"Failed to allocate virtual memory of size {size}. Error: {Marshal.GetLastWin32Error()}"); + } + return pointer; + } + else + { + var pointer = mmap(IntPtr.Zero, (nuint)size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (pointer == new IntPtr(MAP_FAILED)) + { + throw new OutOfMemoryException($"Failed to allocate virtual memory of size {size}. Error: {Marshal.GetLastPInvokeError()}"); + } + return pointer; + } + } + + #endregion + } +} \ No newline at end of file From d1a67f4a1ecf0922793b6c7444b86a86dfc00c87 Mon Sep 17 00:00:00 2001 From: konard Date: Sun, 14 Sep 2025 13:18:19 +0300 Subject: [PATCH 3/3] Remove CLAUDE.md - Claude command completed --- CLAUDE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 58d8716..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/linksplatform/Memory/issues/11 -Your prepared branch: issue-11-fbe64687 -Your prepared working directory: /tmp/gh-issue-solver-1757844600053 - -Proceed. \ No newline at end of file