Files
BQP/srcs/RobotNet10/Commons/RobotNet10.Realtime/LinuxNative.cs
2026-07-13 09:25:40 +07:00

229 lines
7.2 KiB
C#

using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace RobotNet10.Realtime;
/// <summary>
/// Native Linux system calls and constants for realtime operations.
/// </summary>
internal static partial class LinuxNative
{
// Scheduling policies
public const int SCHED_NORMAL = 0;
public const int SCHED_FIFO = 1;
public const int SCHED_RR = 2;
public const int SCHED_BATCH = 3;
public const int SCHED_IDLE = 5;
public const int SCHED_DEADLINE = 6;
// Clock IDs
public const int CLOCK_REALTIME = 0;
public const int CLOCK_MONOTONIC = 1;
public const int CLOCK_PROCESS_CPUTIME_ID = 2;
public const int CLOCK_THREAD_CPUTIME_ID = 3;
public const int CLOCK_MONOTONIC_RAW = 4;
public const int CLOCK_REALTIME_COARSE = 5;
public const int CLOCK_MONOTONIC_COARSE = 6;
public const int CLOCK_BOOTTIME = 7;
public const int CLOCK_REALTIME_ALARM = 8;
public const int CLOCK_BOOTTIME_ALARM = 9;
// Timerfd flags
public const int TFD_NONBLOCK = 0x800;
public const int TFD_CLOEXEC = 0x80000;
// Timerfd timer types
public const int TFD_TIMER_ABSTIME = 0x1;
// CPU set size (for CPU affinity)
public const int CPU_SETSIZE = 1024;
public const int __NCPUBITS = 64;
// Memory lock flags
public const int MCL_CURRENT = 1;
public const int MCL_FUTURE = 2;
public const int MCL_ONFAULT = 4;
// Signal numbers for real-time signals (SIGRTMIN to SIGRTMAX)
public const int SIGRTMIN = 34;
public const int SIGRTMAX = 64;
// Priority ranges
public const int MIN_PRIORITY = 1;
public const int MAX_PRIORITY = 99;
[StructLayout(LayoutKind.Sequential)]
public struct sched_param
{
public int sched_priority;
}
[StructLayout(LayoutKind.Sequential)]
public struct timespec
{
public long tv_sec; // seconds
public long tv_nsec; // nanoseconds
}
[StructLayout(LayoutKind.Sequential)]
public struct itimerspec
{
public timespec it_interval; // timer interval
public timespec it_value; // timer expiration
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct cpu_set_t
{
// Using fixed buffer instead of array with MarshalAs for LibraryImport compatibility
// 16 * 64 = 1024 bits
public fixed ulong __bits[16];
}
// Scheduling functions
[LibraryImport("libc", SetLastError = true)]
public static partial int sched_setscheduler(int pid, int policy, ref sched_param param);
[LibraryImport("libc", SetLastError = true)]
public static partial int sched_getscheduler(int pid);
[LibraryImport("libc", SetLastError = true)]
public static partial int sched_getparam(int pid, ref sched_param param);
[LibraryImport("libc", SetLastError = true)]
public static partial int sched_setparam(int pid, ref sched_param param);
[LibraryImport("libc", SetLastError = true)]
public static partial int sched_get_priority_min(int policy);
[LibraryImport("libc", SetLastError = true)]
public static partial int sched_get_priority_max(int policy);
[LibraryImport("libc", SetLastError = true)]
public static partial int sched_yield();
// CPU affinity functions
[LibraryImport("libc", SetLastError = true)]
public static partial int sched_setaffinity(int pid, IntPtr cpusetsize, ref cpu_set_t mask);
[LibraryImport("libc", SetLastError = true)]
public static partial int sched_getaffinity(int pid, IntPtr cpusetsize, ref cpu_set_t mask);
// CPU set manipulation macros (implemented as functions)
public static unsafe void CPU_ZERO(ref cpu_set_t set)
{
for (int i = 0; i < 16; i++)
{
set.__bits[i] = 0;
}
}
public static unsafe void CPU_SET(int cpu, ref cpu_set_t set)
{
int index = cpu / __NCPUBITS;
int bit = cpu % __NCPUBITS;
if (index < 16)
{
set.__bits[index] |= (1UL << bit);
}
}
public static unsafe void CPU_CLR(int cpu, ref cpu_set_t set)
{
int index = cpu / __NCPUBITS;
int bit = cpu % __NCPUBITS;
if (index < 16)
{
set.__bits[index] &= ~(1UL << bit);
}
}
public static unsafe int CPU_ISSET(int cpu, ref cpu_set_t set)
{
int index = cpu / __NCPUBITS;
int bit = cpu % __NCPUBITS;
if (index >= 16)
{
return 0;
}
return (set.__bits[index] & (1UL << bit)) != 0 ? 1 : 0;
}
public static unsafe int CPU_COUNT(ref cpu_set_t set)
{
int count = 0;
for (int i = 0; i < 16; i++)
{
count += System.Numerics.BitOperations.PopCount(set.__bits[i]);
}
return count;
}
// Memory locking functions
[LibraryImport("libc", SetLastError = true)]
public static partial int mlock(IntPtr addr, IntPtr len);
[LibraryImport("libc", SetLastError = true)]
public static partial int munlock(IntPtr addr, IntPtr len);
[LibraryImport("libc", SetLastError = true)]
public static partial int mlockall(int flags);
[LibraryImport("libc", SetLastError = true)]
public static partial int munlockall();
// Clock functions
[LibraryImport("libc", SetLastError = true)]
public static partial int clock_gettime(int clockid, ref timespec tp);
[LibraryImport("libc", SetLastError = true)]
public static partial int clock_settime(int clockid, ref timespec tp);
[LibraryImport("libc", SetLastError = true)]
public static partial int clock_getres(int clockid, ref timespec res);
// Timerfd functions
[LibraryImport("libc", SetLastError = true)]
public static partial int timerfd_create(int clockid, int flags);
[LibraryImport("libc", SetLastError = true)]
public static partial int timerfd_settime(int fd, int flags, ref itimerspec new_value, ref itimerspec old_value);
[LibraryImport("libc", SetLastError = true)]
public static partial int timerfd_gettime(int fd, ref itimerspec curr_value);
// Process/Thread functions
[LibraryImport("libc", SetLastError = true)]
public static partial int getpid();
[LibraryImport("libc", SetLastError = true)]
public static partial uint gettid();
// Error handling
[LibraryImport("libc")]
public static partial IntPtr __errno_location();
public static int GetLastError()
{
IntPtr errnoPtr = __errno_location();
if (errnoPtr == IntPtr.Zero)
{
return 0;
}
return Marshal.ReadInt32(errnoPtr);
}
public static void ThrowLastError(string operation)
{
int errno = GetLastError();
IntPtr errorMsgPtr = strerror(errno);
string errorMsg = errorMsgPtr != IntPtr.Zero ? Marshal.PtrToStringAnsi(errorMsgPtr) ?? "Unknown error" : "Unknown error";
throw new RealtimeException($"{operation} failed with errno {errno}: {errorMsg}", errno);
}
[LibraryImport("libc")]
private static partial IntPtr strerror(int errno);
}