草庐IT

c - signalfd() 遗漏信号

coder 2023-06-20 原文

在我的程序中,我使用 signalfd 来处理信号并将其与 poll 结合用于异步 IO。下面是我的代码:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/signalfd.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <poll.h>
#include <assert.h>
#include <errno.h>


volatile sig_atomic_t cont = 1;
volatile sig_atomic_t usrcnt = 0;
volatile sig_atomic_t susrcnt = 0;

volatile sig_atomic_t wsig = 0;
volatile sig_atomic_t wtid = 0;

int GetCurrentThreadId()
{
    return syscall(__NR_gettid);
}

void Segv1(int p1, siginfo_t * p2, void * p3)
{
    //printf("SIGSEGV signal on illegal memory access handled by thread: %d\n", GetCurrentThreadId());
    wtid = GetCurrentThreadId();
    wsig = SIGSEGV;
    _exit(SIGSEGV);
}

void Fpe1(int p1 , siginfo_t * p2, void * p3)
{
    //printf is only for test.
    //printf("FPE signal handled by thread: %d\n", GetCurrentThreadId());
    wtid = GetCurrentThreadId();
    wsig = SIGFPE;
    _exit(SIGFPE);
}

void User1(int p1 , siginfo_t * p2, void * p3)
{
    printf("User signal 1 handled by thread: %d\n", GetCurrentThreadId());
    ++susrcnt;
    wtid = GetCurrentThreadId();
    wsig = SIGUSR1;
}


void* ThreadFunc (void* d)
{

    //Let us use signalfd.
    int sfd;
    sigset_t mask;

    /* We will handle SIGTERM and SIGINT. */
    sigemptyset (&mask);
    sigaddset (&mask, SIGUSR1);

    /* Create a file descriptor from which we will read the signals. */
    sfd = signalfd (-1, &mask, 0);
    if (sfd < 0) {
        printf ("signalfd failed with %d\n", errno);
        return NULL;
    }

    pthread_sigmask(SIG_BLOCK, &mask, NULL);

  /* This is the main loop */
        struct pollfd pfd[1];
        int ret;
        ssize_t bytes;

        pfd[0].fd = sfd;
        pfd[0].events = POLLIN | POLLERR | POLLHUP;

        for (;;) {
                ret = poll(pfd, 1, -1);

                /* Bail on errors (for simplicity) */
                assert(ret > 0);
                assert(pfd[0].revents & POLLIN);

                /* We have a valid signal, read the info from the fd */
                struct signalfd_siginfo info;
                bytes = read(sfd, &info, sizeof(info));
                assert(bytes == sizeof(info));

                unsigned sig = info.ssi_signo;
                unsigned user = info.ssi_uid;

                if (sig == SIGUSR1) {
                    ++usrcnt;
                    printf ("Got SIGUSR1 by POLL in thread: %d: Handler count: %d,  %d\n", GetCurrentThreadId(), susrcnt, usrcnt);
                }
        }

    /* Close the file descriptor if we no longer need it. */
    close (sfd);

    return NULL;
}


int main()
{

    const int numthreads = 1;
    sigset_t sset;
    struct sigaction act;
    int sleepval = 15;
    int pid;
    int i;
        int * a = 0;
    //*a = 1;
    int c=0;
    //c = 0;
    int b;


    printf("My PID: %d\n", getpid());
    printf("SIGSEGV: %d\nSIGFPE: %d\nSIGUSR1: %d\n", SIGSEGV, SIGFPE, SIGUSR1);
    //Create a thread for signal
    memset(&act, 0, sizeof act);
    act.sa_sigaction = User1;
    act.sa_flags    = SA_SIGINFO;

    //Set Handler for SIGUSR1 signal.
    if(sigaction(SIGUSR1, &act, NULL)<0) {
        fprintf(stderr, "sigaction failed\n");
        return 1;
    }


    //Set handler for SIGSEGV signal.
    act.sa_sigaction    = Segv1;
    sigaction(SIGSEGV, &act, NULL);

    //Set handler for SIGFPE (floating point exception) signal.
    act.sa_sigaction    = Fpe1;
    sigaction(SIGFPE, &act, NULL);


    sigemptyset(&sset);
    sigaddset(&sset, SIGUSR1);

    sigprocmask(SIG_UNBLOCK, &sset, NULL);

    pthread_t tid[numthreads];
    for(i=0;i<numthreads;++i)
        pthread_create(&tid[i], NULL, ThreadFunc, NULL);

    //Block the signal for main thread so that other thread handles the the signal.
    pthread_sigmask(SIG_BLOCK, &sset, NULL);

    sleep(numthreads/2);

    //Raise user signal SIGUSR1.
    //raise(SIGUSR1);
    pid = fork();
    if(pid) {
        while(sleepval) {
            sleepval = sleep(sleepval);
            if(sleepval)
                switch(wsig) {
                    case SIGSEGV:
                        printf("[Main] Segmenation fault in thread: %d\n", wtid);
                        exit(1);
                        break;
                    case SIGFPE:
                        printf("[Main] Floating point exception in thread: %d\n", wtid);
                        exit(1);
                        break;
                    case SIGUSR1:
                        printf("[Main] User 1 signal in thread: %d\n", wtid);
                        break;
                    default:
                        printf("[Main] Unhandled signal: %d in thread: %d\n", wsig, wtid);
                        break;
                }
        }

    } else {
         sleep(1); //To avoid race between signal handler and signal fd.

        for(i=0;i<10;++i) {
            //If sleep is not used, signal SIGUSR1 will be handled one time in parent
            //as other signals will be ignored while SIGUSR1 is being handled.
            sleep(1);
            //Problem is here. When the sleep(1) is commented out, it missed the signals.
            kill(getppid(), SIGUSR1);
        }
        return 0;
    }

    return 0;
}

在程序中,进程生成一个线程,该线程创建 signalfd 并开始使用 poll。然后进程产生一个子进程,该子进程将 SIGUSR1 发送到父进程。当以 1s 的间隔发送信号时,它会处理所有信号。然而,当 sleep 被移除时,它错过了通知。

我想知道如果 signalfd 正在处理相同的信号,它是否也会丢弃信号通知。另外,信号处理程序和 signalfd 之间的优先顺序是什么?

最佳答案

如果一个进程有多个标准(即:非实时)信号挂起,操作系统可能会决定将多个相同类型的信号合并为一个。

来自 POSIX :

2.4.1 Signal Generation and Delivery

[...]

If a subsequent occurrence of a pending signal is generated, it is implementation-defined as to whether the signal is delivered or accepted more than once in circumstances other than those in which queuing is required.

默认情况下,标准信号不排队。使标准信号排队的唯一方法是使用 sigqueue() 发出它们.

关于c - signalfd() 遗漏信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25717766/

有关c - signalfd() 遗漏信号的更多相关文章

  1. ruby-on-rails - 第 1 行中的引号缺失或遗漏 (CSV::MalformedCSVError) - 2

    我在ruby​​/rails中导入此CSV文件时遇到问题我得到的错误信息是这样的:Missingorstrayquoteinline1(CSV::MalformedCSVError)但我不确定发生了什么,因为我的CSV看起来非常好。以下是示例数据:"lesley_grades","lesley_id","last","first","active","site","cohort","section","sections_title","faculty","completed_term_cred","term","sec_start_date","sec_end_date","grade

  2. Verilog使用inout信号的方法 - 2

    目录一、inout在设计文件中的使用方法1.1、inout的第一种使用方法1.2、inout实现的第二种使用方法1.3、inout使用总结 二、inout在仿真测试中的使用方法一、inout在设计文件中的使用方法在FPGA的设计过程中,有时候会遇到双向信号(既能作为输出,也能作为输入的信号叫双向信号)。比如,IIC总线中的SDA信号就是一个双向信号,QSPIFlash的四线操作的时候四根信号线均为双向信号。在Verilog中用关键字inout定义双向信号,这里总结一下双向信号的处理方法。1.1、inout的第一种使用方法  实际上,双向信号的本质是由一个三态门组成的,三态门可以输出高电平,低电

  3. ruby - 在 Ruby 中使用 GTK3 自定义信号 - 2

    我想从gtk3中的Widget发出自定义信号。在GTK2中,有一个名为signal_new的函数来创建一个新信号。您可以在此处查看示例:https://github.com/ruby-gnome2/ruby-gnome2/blob/ec373f87e672dbeeaa157f9148d18b34713bb90e/glib2/sample/type-register.rb在GTK3中,这个功能似乎不再可用。那么在ruby​​的GTK3中创建自定义信号的新方法是什么? 最佳答案 GTK3更改为使用define_signal方法而不是si

  4. ruby - QtRuby 使用参数/参数连接信号和槽 - 2

    我想知道如何连接到带参数的信号(使用Rubyblock)。我知道如何连接到一个不带参数的:myCheckbox.connect(SIGNAL:clicked){doStuff}但是,这不起作用:myCheckbox.connect(SIGNAL:toggle){doStuff}它不起作用,因为切换槽采用参数voidQAbstractButton::toggled(boolchecked)。我怎样才能让它与参数一起工作?谢谢。 最佳答案 对您的问题的简短回答是,您必须使用slots方法声明要连接的插槽的方法签名:classMainGU

  5. ruby - 发送信号时运行代码,但不要在 Ruby 中捕获信号 - 2

    我有在服务器上运行的代码,在服务器硬关闭之前,发送了一个信号SIGTERM让我的代码知道它需要清理。我想在发生这种情况时运行代码并将信号发送回同一个程序,以便任何其他需要清理的代码都可以这样做。我不想捕获信号或改变信号行为,我只需要在我的程序的其余部分解释SIGTERM之前运行一些东西。目前我可以做类似的事情Signal.trap('TERM')doputs"Gracefulshutdown"exitend但如果同一个应用中的多段代码试图做同样的事情,它就不起作用了。例如:Signal.trap('TERM')doputs"Gracefulshutdown"exitendSignal.

  6. ruby-on-rails - Simplecov 覆盖率报告似乎遗漏了某些行 - 2

    在澄清了simplecov如何确定一条线是否已被测试执行之后。我有以下方法:defover?end_at其中end_at是对象的ActiveRecord属性。在以下规范中进行了练习:describeCalendarEntrydoit'candeterminethataneventhasended'do@entry.end_at=1.day.ago@entry.over?.shouldbe_trueendend在覆盖范围内运行规范后,它显示以下结果:我已经在Debug模式下运行了测试,并在此行上设置了一个断点,并确认规范确实符合它。这并不仅限于此方法中的这一行,包括使用ActiveRec

  7. ruby - 如何测试 RSpec 中的信号处理,特别是 SIGTERM 的处理? - 2

    Heroku可能会出于各种原因向您的应用程序发送SIGTERM,因此我创建了一个处理程序来处理一些清理工作,以防发生这种情况。一些谷歌搜索没有给出任何关于如何在RSpec中测试它的答案或示例。这是基本代码:Signal.trap('TERM')docleanupenddefcleanupputs"doingsomecleanupstuff"...exitend当程序收到SIGTERM时,测试调用此清理方法的最佳方法是什么? 最佳答案 使用Process.kill'TERM',0将信号发送到RSpec并测试调用处理程序。确实,如果信号

  8. ruby - 我怎样才能告诉 unicorn 理解 Heroku 的信号? - 2

    也许你已经看到了这个......2012-03-07T15:36:25+00:00heroku[web.1]:StoppingprocesswithSIGTERM2012-03-07T15:36:36+00:00heroku[web.1]:StoppingprocesswithSIGKILL2012-03-07T15:36:36+00:00heroku[web.1]:ErrorR12(Exittimeout)->Processfailedtoexitwithin10secondsofSIGTERM2012-03-07T15:36:38+00:00heroku[web.1]:Proces

  9. ruby - Windows 上有哪些 Process.kill 信号可用? - 2

    来自Process.kill的文档:Sendsthegivensignaltothespecifiedprocessid(s)ifpidispositive.IfpidiszerosignalissenttoallprocesseswhosegroupIDisequaltothegroupIDoftheprocess.signalmaybeanintegersignalnumberoraPOSIXsignalname(eitherwithorwithoutaSIGprefix).Ifsignalisnegative(orstartswithaminussign),killsproces

  10. 互联网时代“陨落”,国家发布元宇宙战略的信号对失业和担心失业的我们带来了什么启迪? - 2

    互联网这头“猪”真的掉下来了流量红利已经一去不复返了!3年前业界其实已经发出各种密集信号,在当时无论是BAT还是一些经济学家在3年前都已经预测过,互联网的流量模式已经衰竭,并且它将一去不复返。曾经处于互联网大潮的我们这一代人有喜有有悲也有感慨。还在4-5年前不少程序员会发觉在一个地方工作一年再跳一家公司,工资翻倍是至少的。其实这不是能力的表现这只不过是因此我们赶上了互联网流利红利、风投资本红利的“风口”而己。“赶上风口就连老母猪都能上树"用于形容当时的情形一点不为过。可是这个“风”这次是真的过去了,因此这头“猪”掉了下来,而且这次摔了还挺狠,直接给摔成了肉饼。业务模式、生态、环境的变革是时代的

随机推荐