P/Invoke: 致命错误。无效程序:试图从运行时类型安全代码调用 NativeCallable 方法
P/Invoke: Fatal error. Invalid Program: attempted to call a NativeCallable method from runtime-typesafe code
我正在尝试使用来自 libstd 的 sigaction 在 Linux 系统 (Ubuntu) 的后台任务中捕获终止信号。这是我的程序 class 和 DllImport 声明:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace Signal
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var pid = LibStd.GetPid();
Console.WriteLine($"PID: {pid}");
var sa = new Sigaction()
{
Handler = SignalHandler
};
LibStd.SigEmptySet(sa.Mask);
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sa));
Marshal.StructureToPtr(sa, ptr, true);
_ = Task.Run(async() =>
{
while (true)
{
// Check SIGUSR1
if (LibStd.Sigaction(10, ptr, IntPtr.Zero) == -1)
{
// error
}
await Task.Delay(1);
}
});
while (true)
{
// Do something
}
}
static LibStd.SignalHandler SignalHandler = new LibStd.SignalHandler(Handler);
static void Handler(int sig)
{
Console.WriteLine($"RECEIVED SIGNAL {sig}");
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct Sigaction
{
public LibStd.SignalHandler Handler;
public IntPtr Mask;
public int Flags;
}
internal static class LibStd
{
private const string LibName = "c";
[DllImport(LibName, EntryPoint = "getpid")]
internal static extern int GetPid();
[DllImport(LibName, EntryPoint = "sigaction", CallingConvention = CallingConvention.Cdecl)]
internal static extern int Sigaction(int sig, IntPtr act, IntPtr oldact);
[DllImport(LibName, EntryPoint = "sigemptyset", CallingConvention = CallingConvention.Cdecl)]
internal static extern int SigEmptySet(IntPtr mask);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void SignalHandler(int t);
}
}
我需要在后台检查信号,因为我想将来把这段代码放在桌面 GUI 应用程序中,这样信号处理就不会阻塞 UI 线程。
但是,当我 运行 这个程序,然后调用 kill -SIGUSR1 <pid>
它输出到控制台以下错误:
致命错误。无效程序:试图从 运行 时间类型安全代码调用 NativeCallable 方法。
如果我将信号处理放入主 while (true) { }
循环中,它会按预期工作。
如果有人能帮我修复它就太好了。谢谢
对于Ubuntu18我发现需要的结构是
[StructLayout(LayoutKind.Sequential)]
internal struct Sigaction
{
public LibStd.SignalHandler Handler;
public IntPtr Mask;
public int Flags;
public LibStd.SignalHandler sa_restorer;
}
考虑不启动信号处理线程
static private void ListenToSignal()
{
var sa = new Sigaction()
{
Handler = SignalHandler
};
LibStd.SigEmptySet(sa.Mask);
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sa));
Marshal.StructureToPtr(sa, ptr, true);
if (LibStd.Sigaction(10, ptr, IntPtr.Zero) == -1)
{
Console.WriteLine("Sigaction -1");
}
Console.WriteLine("Sigaction done");
}
这将在主线程上设置处理。当信号到达时,它也会得到处理。不需要一直轮询 Sigaction
我正在尝试使用来自 libstd 的 sigaction 在 Linux 系统 (Ubuntu) 的后台任务中捕获终止信号。这是我的程序 class 和 DllImport 声明:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace Signal
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var pid = LibStd.GetPid();
Console.WriteLine($"PID: {pid}");
var sa = new Sigaction()
{
Handler = SignalHandler
};
LibStd.SigEmptySet(sa.Mask);
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sa));
Marshal.StructureToPtr(sa, ptr, true);
_ = Task.Run(async() =>
{
while (true)
{
// Check SIGUSR1
if (LibStd.Sigaction(10, ptr, IntPtr.Zero) == -1)
{
// error
}
await Task.Delay(1);
}
});
while (true)
{
// Do something
}
}
static LibStd.SignalHandler SignalHandler = new LibStd.SignalHandler(Handler);
static void Handler(int sig)
{
Console.WriteLine($"RECEIVED SIGNAL {sig}");
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct Sigaction
{
public LibStd.SignalHandler Handler;
public IntPtr Mask;
public int Flags;
}
internal static class LibStd
{
private const string LibName = "c";
[DllImport(LibName, EntryPoint = "getpid")]
internal static extern int GetPid();
[DllImport(LibName, EntryPoint = "sigaction", CallingConvention = CallingConvention.Cdecl)]
internal static extern int Sigaction(int sig, IntPtr act, IntPtr oldact);
[DllImport(LibName, EntryPoint = "sigemptyset", CallingConvention = CallingConvention.Cdecl)]
internal static extern int SigEmptySet(IntPtr mask);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void SignalHandler(int t);
}
}
我需要在后台检查信号,因为我想将来把这段代码放在桌面 GUI 应用程序中,这样信号处理就不会阻塞 UI 线程。
但是,当我 运行 这个程序,然后调用 kill -SIGUSR1 <pid>
它输出到控制台以下错误:
致命错误。无效程序:试图从 运行 时间类型安全代码调用 NativeCallable 方法。
如果我将信号处理放入主 while (true) { }
循环中,它会按预期工作。
如果有人能帮我修复它就太好了。谢谢
对于Ubuntu18我发现需要的结构是
[StructLayout(LayoutKind.Sequential)]
internal struct Sigaction
{
public LibStd.SignalHandler Handler;
public IntPtr Mask;
public int Flags;
public LibStd.SignalHandler sa_restorer;
}
考虑不启动信号处理线程
static private void ListenToSignal()
{
var sa = new Sigaction()
{
Handler = SignalHandler
};
LibStd.SigEmptySet(sa.Mask);
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sa));
Marshal.StructureToPtr(sa, ptr, true);
if (LibStd.Sigaction(10, ptr, IntPtr.Zero) == -1)
{
Console.WriteLine("Sigaction -1");
}
Console.WriteLine("Sigaction done");
}
这将在主线程上设置处理。当信号到达时,它也会得到处理。不需要一直轮询 Sigaction