using System; using System.Runtime.InteropServices; namespace RobotNet10.Realtime; /// /// Provides memory locking functionality for real-time applications. /// Prevents memory from being swapped to disk, ensuring deterministic access times. /// public static class MemoryLock { /// /// Locks a specific memory region to prevent swapping. /// /// Pointer to the memory region /// Length of the memory region in bytes /// Thrown when the operation fails. public static void Lock(IntPtr address, IntPtr length) { int result = LinuxNative.mlock(address, length); if (result != 0) { LinuxNative.ThrowLastError("mlock"); } } /// /// Unlocks a specific memory region. /// /// Pointer to the memory region /// Length of the memory region in bytes /// Thrown when the operation fails. public static void Unlock(IntPtr address, IntPtr length) { int result = LinuxNative.munlock(address, length); if (result != 0) { LinuxNative.ThrowLastError("munlock"); } } /// /// Locks all current and future memory pages for the process. /// /// Lock flags (MCL_CURRENT, MCL_FUTURE, MCL_ONFAULT) /// Thrown when the operation fails. public static void LockAll(MemoryLockFlags flags) { int result = LinuxNative.mlockall((int)flags); if (result != 0) { LinuxNative.ThrowLastError("mlockall"); } } /// /// Unlocks all memory pages for the process. /// /// Thrown when the operation fails. public static void UnlockAll() { int result = LinuxNative.munlockall(); if (result != 0) { LinuxNative.ThrowLastError("munlockall"); } } /// /// Locks a managed array to prevent swapping. /// /// Type of array elements /// Array to lock /// GCHandle that must be kept alive while the memory is locked public static GCHandle LockArray(T[] array) { GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned); try { IntPtr address = handle.AddrOfPinnedObject(); IntPtr length = new IntPtr(Marshal.SizeOf() * array.Length); Lock(address, length); } catch { handle.Free(); throw; } return handle; } } /// /// Memory locking flags. /// [Flags] public enum MemoryLockFlags { /// /// Lock all pages currently mapped into the address space of the process. /// Current = LinuxNative.MCL_CURRENT, /// /// Lock all pages that will become mapped into the address space of the process in the future. /// Future = LinuxNative.MCL_FUTURE, /// /// Lock pages that are currently mapped into the address space of the process and mark all pages /// that will become mapped into the address space of the process in the future to be locked /// when they are faulted in. /// OnFault = LinuxNative.MCL_ONFAULT, }