229 lines
7.2 KiB
C#
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);
|
|
}
|
|
|