首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用epoll_wait和signalfd处理信号

使用epoll_wait和signalfd处理信号
EN

Stack Overflow用户
提问于 2017-04-04 23:55:24
回答 3查看 4.8K关注 0票数 6

我正在使用套接字和系统调用编写自己的echo server。我正在使用epoll同时处理许多不同的客户端,并且使用客户端完成的所有操作都是非阻塞的。当服务器启动且不执行任何操作时,它处于epoll_wait中。现在我想添加使用信号关闭服务器的可能性。例如,我在bash terminal中启动服务器,然后按ctrl-c,服务器就会以某种方式处理SIGINT。我的计划是使用signalfd。我使用以下代码创建新的signalfd并将其添加到epoll实例中:

    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGTERM);
    sigaddset(&mask, SIGINT);
    signal_fd = signalfd(-1, &mask, 0);

    epoll_event event;
    event.data.fd = signal_fd;
    event.events = EPOLLIN;
    epoll_ctl(fd, EPOLL_CTL_ADD, signal_fd, &event);

然后我期望,当epoll在等待时,我按下ctrl-cepoll上的事件发生,它被唤醒,然后我用以下代码处理信号:

    if (events[i].data.fd == signal_fd)
    {
        //do something
        exit(0);
    }

尽管在现实中,服务器只是停止而不处理信号。我做错了什么,解决问题的正确方法是什么?如果我对信号的理解不正确,那么应该在哪里使用signalfd

EN

回答 3

Stack Overflow用户

发布于 2017-04-05 00:12:05

当被信号中断时,epoll_wait返回-1errno == EINTR。在这种情况下,您需要从signal_fd执行read

将信号的信号处理程序设置为SIG_IGN,否则信号可能会终止应用程序。

请参阅man signal 7

以下接口在被信号处理程序中断后永远不会重新启动,无论是否使用SA_RESTART;当被信号处理程序中断时,它们总是失败并显示错误EINTR

  • 文件描述符多路复用接口: epoll_wait(2)、epoll_pwait(2)、poll(2)、ppoll(2)、select(2)和pselect(2)。
票数 5
EN

Stack Overflow用户

发布于 2019-06-14 01:46:44

,但在现实中,服务器只是停止而不处理信号。我做错了什么,解决问题的正确方法是什么?如果我没有正确理解信号,在什么地方应该使用signalfd?

信号处理程序是针对每个进程的。您将信号处理程序保留为默认值,即终止进程。

所以你需要添加像这样的东西,

struct sigaction action;
std::memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = your_handler;
sigaction(signum, &action, NULL);

对于您希望应用程序接收中断的每个signum。还要处理sigaction的返回值。我的经验是,如果你使用SIG_IGN作为处理程序,你仍然会从“外部”中断像epoll_pwait这样的系统调用,但当你试图通过使用pthread_kill将信号直接发送到线程来从程序本身唤醒线程时,它不会起作用。

接下来,您需要屏蔽来自每个线程的所有信号,以便默认情况下没有线程会收到它(否则会唤醒一个随机线程来处理该信号)。要做到这一点,最简单的方法是在创建线程之前在main中完成。

例如,

sigset_t all_signals;
sigemptyset(&all_signals);
sigaddset(&all_signals, signum); // Repeat for each signum that you use.
sigprocmask(SIG_BLOCK, &all_signals, NULL);

然后,当您希望每个线程接收信号时,取消阻塞该线程的信号。

如果您使用signalfd,那么您不希望取消阻止它们-系统调用本身取消阻止信号,只传递适当掩码(为signalfd设置位)(它使用传递的掩码取消阻止)。另请参阅signalfd的手册页)。

epoll_pwait的工作方式有所不同;与pselect一样,您可以解锁您感兴趣的信号。您可以为该信号设置一个设置标志的处理程序(见上)。然后在调用epoll_pwait之前阻塞信号,然后测试标志并处理它,然后调用epoll_pwait而不首先解除阻塞信号。在epoll_wait返回之后,您可以再次取消阻塞该信号,以便可以再次调用您的处理程序。

票数 1
EN

Stack Overflow用户

发布于 2021-04-26 19:12:32

在创建信号FD之前,必须阻止所有要用信号FD处理的信号。否则,这些信号仍然会中断被阻塞的系统调用,如您所观察到的epoll_wait()

另请参阅signalfd(2) man page

通常情况下,应该使用sigprocmask(2)阻塞通过文件描述符接收的信号集,以防止信号根据其默认配置进行处理。

因此,您必须像这样更改您的示例:

    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGTERM);
    sigaddset(&mask, SIGINT);
    int r = sigprocmask(SIG_BLOCK, &mask, 0);
    if (r == -1) {
        // XXX handle errors
    }
    signal_fd = signalfd(-1, &mask, 0);
    if (signal_fd == -1) {
        // XXX handle errors
    }

    epoll_event event;
    event.data.fd = signal_fd;
    event.events = EPOLLIN;
    r = epoll_ctl(fd, EPOLL_CTL_ADD, signal_fd, &event);
    if (r == -1) {
        // XXX handle errors
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43212106

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档