linux 平台上 C# 中的自定义 posix 信号不起作用
Custom posix signal in C# on a linux platform does not work
问题
我正在尝试将 linux 中的信号发送到 Linux 中 dotnet 核心中的 C# 线程。我的测试代码适用于 SIGARAM,但不适用于映射到 SIGRTMIN# 的自定义信号。 sigwait
在线程上永远不会 returns 当主线程引发自定义信号时。
C++ 版本运行良好。 C++ 和 C# 版本几乎相同。谁能弄清楚为什么它不起作用?
我的最终目标是捕捉来自设备驱动程序的信号。
C++ 版本
//https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/sigwaiti.htm
//g++ -Wall -O2 example.cpp -o example -pthread
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <thread>
void catcher( int sig ) {
printf( "Signal catcher called for signal %d\n", sig );
}
void timestamp( const char *str ) {
time_t t;
time( &t );
printf( "The time %s is %s\n", str, ctime(&t) );
}
void on_sigusr1(int sig)
{
// Note: Normally, it's not safe to call almost all library functions in a
// signal handler, since the signal may have been received in a middle of a
// call to that function.
printf("SIGUSR1 received!\n");
}
#define SIG_SYSTEM (SIGRTMIN+7)
void run()
{
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
sigemptyset( &sigact.sa_mask );
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction( SIG_SYSTEM, &sigact, NULL );
sigemptyset( &waitset );
sigaddset( &waitset, SIG_SYSTEM );
sigprocmask( SIG_BLOCK, &waitset, NULL );
timestamp( "before sigwaitinfo()" );
// int result = sigwaitinfo( &waitset, &info );
int sig;
int result = sigwait( &waitset, &sig );
if( sig == SIG_SYSTEM )
printf( "sigwaitinfo() returned for signal %d\n",
info.si_signo );
else {
printf( "sigwait() sig %d\n", sig );
printf( "sigwait() returned code %d\n", result );
printf( "sigwait() returned error number %d\n", errno );
perror( "sigwait() function failed\n" );
}
timestamp( "after sigwaitinfo()" );
}
int main( int argc, char *argv[] ) {
int result = 0;
signal(SIG_SYSTEM, &on_sigusr1);
sigset_t waitset;
sigemptyset( &waitset );
sigaddset( &waitset, SIG_SYSTEM );
sigprocmask( SIG_BLOCK, &waitset, NULL );
std::thread tx(run);
sleep(5);
//alarm( 5 );
//result = raise(SIG_SYSTEM);
result = kill(getpid(), SIG_SYSTEM);
printf( "kill(%d) %d\n", SIG_SYSTEM, result);
tx.join();
return( result );
}
C# 版本
但是 C# 中的测试程序不起作用。
using System;
using static Tmds.Linux.LibC;
using Tmds.Linux;
using System.Runtime.InteropServices;
delegate void SignalCallback(int sig);
namespace example
{
class Program
{
static void catcher(int sig)
{
Console.WriteLine($"Signal catcher called for signal {sig}");
}
static void timestamp(string str)
{
Console.WriteLine($"The time {str} is {DateTime.Now}");
}
static System.Threading.Thread Thread;
static int SIG_SYSTEM = SIGRTMIN + 7;
static unsafe void Run()
{
int result = 0;
sigaction sigact = new sigaction();
sigset_t waitset = new sigset_t();
siginfo_t info = new siginfo_t();
sigset_t* ptr = &sigact.sa_mask;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
SignalCallback callback = new SignalCallback(catcher);
sigact.sa_handler = (void*)Marshal.GetFunctionPointerForDelegate(callback);
sigaction(SIG_SYSTEM, &sigact, null);
sigemptyset(&waitset);
sigaddset(&waitset, SIG_SYSTEM);
sigprocmask(SIG_BLOCK, &waitset, null);
timestamp("before sigwaitinfo()");
//result = sigwaitinfo(&waitset, &info);
int sig;
result = sigwait(&waitset, &sig);
// after it's last usage by unmanaged code
GC.KeepAlive(callback);
if (sig == SIG_SYSTEM)
Console.WriteLine($"sigwaitinfo() returned for signal {info.si_signo}");
else
{
Console.WriteLine($"sigwait() sig {sig}");
Console.WriteLine($"sigwait() returned code {result}");
Console.WriteLine($"sigwait() returned error number {errno}");
Console.WriteLine("sigwait() function failed");
}
timestamp("after sigwaitinfo()");
}
static unsafe void Main(string[] args)
{
sigset_t waitset = new sigset_t();
sigemptyset(&waitset);
sigaddset(&waitset, SIG_SYSTEM);
sigprocmask(SIG_BLOCK, &waitset, null);
Thread = new System.Threading.Thread(Run);
Thread.Start();
//alarm(10);
sleep(5);
int result = kill(getpid(), SIG_SYSTEM);
Console.WriteLine($"kill({SIG_SYSTEM}) {result}");
Thread.Join();
}
}
}
环境
- VisualStudio 专业版 2019 16.9.4
- dotnet 核心 SDK 3.1
- Ubuntu 在 WSL
- Tmds.Linux 0.5.0
我能够在写入一个小的 .so 文件时收到信号。
static void (*_callback)(int, int);
void catcher(int sig, siginfo_t* info, void* context) {
int* sival_int = &info->si_int;
_callback(sig, sival_int[1]);
}
extern "C" void setaction(int sig, void *callback)
{
_callback = (void(*)(int, int))callback;
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = catcher;
sigaction(sig, &sigact, NULL);
}
delegate void SignalCallback(int sig, int info);
static SignalCallback cb = Callback;
[DllImport("signalhandle.so")]
static extern void setaction(int sig, SignalCallback callback);
//Call this on the main thread.
public static void Start()
{
setaction(SIG_SYSTEM, cb);
}
private static void Callback(int sig, int info)
{
}
问题
我正在尝试将 linux 中的信号发送到 Linux 中 dotnet 核心中的 C# 线程。我的测试代码适用于 SIGARAM,但不适用于映射到 SIGRTMIN# 的自定义信号。 sigwait
在线程上永远不会 returns 当主线程引发自定义信号时。
C++ 版本运行良好。 C++ 和 C# 版本几乎相同。谁能弄清楚为什么它不起作用?
我的最终目标是捕捉来自设备驱动程序的信号。
C++ 版本
//https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/sigwaiti.htm
//g++ -Wall -O2 example.cpp -o example -pthread
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <thread>
void catcher( int sig ) {
printf( "Signal catcher called for signal %d\n", sig );
}
void timestamp( const char *str ) {
time_t t;
time( &t );
printf( "The time %s is %s\n", str, ctime(&t) );
}
void on_sigusr1(int sig)
{
// Note: Normally, it's not safe to call almost all library functions in a
// signal handler, since the signal may have been received in a middle of a
// call to that function.
printf("SIGUSR1 received!\n");
}
#define SIG_SYSTEM (SIGRTMIN+7)
void run()
{
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
sigemptyset( &sigact.sa_mask );
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction( SIG_SYSTEM, &sigact, NULL );
sigemptyset( &waitset );
sigaddset( &waitset, SIG_SYSTEM );
sigprocmask( SIG_BLOCK, &waitset, NULL );
timestamp( "before sigwaitinfo()" );
// int result = sigwaitinfo( &waitset, &info );
int sig;
int result = sigwait( &waitset, &sig );
if( sig == SIG_SYSTEM )
printf( "sigwaitinfo() returned for signal %d\n",
info.si_signo );
else {
printf( "sigwait() sig %d\n", sig );
printf( "sigwait() returned code %d\n", result );
printf( "sigwait() returned error number %d\n", errno );
perror( "sigwait() function failed\n" );
}
timestamp( "after sigwaitinfo()" );
}
int main( int argc, char *argv[] ) {
int result = 0;
signal(SIG_SYSTEM, &on_sigusr1);
sigset_t waitset;
sigemptyset( &waitset );
sigaddset( &waitset, SIG_SYSTEM );
sigprocmask( SIG_BLOCK, &waitset, NULL );
std::thread tx(run);
sleep(5);
//alarm( 5 );
//result = raise(SIG_SYSTEM);
result = kill(getpid(), SIG_SYSTEM);
printf( "kill(%d) %d\n", SIG_SYSTEM, result);
tx.join();
return( result );
}
C# 版本
但是 C# 中的测试程序不起作用。
using System;
using static Tmds.Linux.LibC;
using Tmds.Linux;
using System.Runtime.InteropServices;
delegate void SignalCallback(int sig);
namespace example
{
class Program
{
static void catcher(int sig)
{
Console.WriteLine($"Signal catcher called for signal {sig}");
}
static void timestamp(string str)
{
Console.WriteLine($"The time {str} is {DateTime.Now}");
}
static System.Threading.Thread Thread;
static int SIG_SYSTEM = SIGRTMIN + 7;
static unsafe void Run()
{
int result = 0;
sigaction sigact = new sigaction();
sigset_t waitset = new sigset_t();
siginfo_t info = new siginfo_t();
sigset_t* ptr = &sigact.sa_mask;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
SignalCallback callback = new SignalCallback(catcher);
sigact.sa_handler = (void*)Marshal.GetFunctionPointerForDelegate(callback);
sigaction(SIG_SYSTEM, &sigact, null);
sigemptyset(&waitset);
sigaddset(&waitset, SIG_SYSTEM);
sigprocmask(SIG_BLOCK, &waitset, null);
timestamp("before sigwaitinfo()");
//result = sigwaitinfo(&waitset, &info);
int sig;
result = sigwait(&waitset, &sig);
// after it's last usage by unmanaged code
GC.KeepAlive(callback);
if (sig == SIG_SYSTEM)
Console.WriteLine($"sigwaitinfo() returned for signal {info.si_signo}");
else
{
Console.WriteLine($"sigwait() sig {sig}");
Console.WriteLine($"sigwait() returned code {result}");
Console.WriteLine($"sigwait() returned error number {errno}");
Console.WriteLine("sigwait() function failed");
}
timestamp("after sigwaitinfo()");
}
static unsafe void Main(string[] args)
{
sigset_t waitset = new sigset_t();
sigemptyset(&waitset);
sigaddset(&waitset, SIG_SYSTEM);
sigprocmask(SIG_BLOCK, &waitset, null);
Thread = new System.Threading.Thread(Run);
Thread.Start();
//alarm(10);
sleep(5);
int result = kill(getpid(), SIG_SYSTEM);
Console.WriteLine($"kill({SIG_SYSTEM}) {result}");
Thread.Join();
}
}
}
环境
- VisualStudio 专业版 2019 16.9.4
- dotnet 核心 SDK 3.1
- Ubuntu 在 WSL
- Tmds.Linux 0.5.0
我能够在写入一个小的 .so 文件时收到信号。
static void (*_callback)(int, int);
void catcher(int sig, siginfo_t* info, void* context) {
int* sival_int = &info->si_int;
_callback(sig, sival_int[1]);
}
extern "C" void setaction(int sig, void *callback)
{
_callback = (void(*)(int, int))callback;
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = catcher;
sigaction(sig, &sigact, NULL);
}
delegate void SignalCallback(int sig, int info);
static SignalCallback cb = Callback;
[DllImport("signalhandle.so")]
static extern void setaction(int sig, SignalCallback callback);
//Call this on the main thread.
public static void Start()
{
setaction(SIG_SYSTEM, cb);
}
private static void Callback(int sig, int info)
{
}