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

Posted

技术标签:

【中文标题】linux 平台上 C# 中的自定义 posix 信号不起作用【英文标题】:Custom posix signal in C# on a linux platform does not work 【发布时间】:2021-08-16 05:20:07 【问题描述】:

问题

我正在尝试将 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 %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 WSL 上的 Ubuntu Tmds.Linux 0.5.0

【问题讨论】:

【参考方案1】:

我能够得到一个写入一个小 .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 平台上 C# 中的自定义 posix 信号不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Linux C++ pthread是什么缩写?(POSIX Threads)<pthread.h>

.NET 中的自定义 ORM

在 C# 中的自定义 appdomain 中加载 dll

ASP.NET C# 中的自定义控件

App.config C# 中的自定义配置部分

Java和C#中的自定义元数据