在linux平台上,C#中的自定义posix信号不起作用



问题

我正试图在linux中向linux中的dotnet内核中的C#线程发送一个信号。我的测试代码使用SIGARAM,但不使用到SIGRTMIN#的自定义信号映射。当主线程引发自定义信号时,线程上的sigwait永远不会返回。

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 %dn", sig );
}
void timestamp( const char *str ) {
time_t t;
time( &t );
printf( "The time %s is %sn", 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 %dn",
info.si_signo );
else {
printf( "sigwait() sig %dn", sig );
printf( "sigwait() returned code %dn", result );
printf( "sigwait() returned error number %dn", errno );
perror( "sigwait() function failedn" );
}
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) %dn", 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 Professional 2019 16.9.4
  • dotnet核心SDK 3.1
  • WSL上的Ubuntu
  • 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)
{
}

最新更新