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,
}