Files
Denso/srcs/RobotNet10/Commons/RobotNet10.Realtime/MemoryLock.cs
2026-07-03 16:31:37 +07:00

117 lines
3.8 KiB
C#

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