コアダンプの数だけ強くなれるよ

見習いエンジニアの備忘log

シグナル受信をepollで監視

Linuxのsignalfdを使ってシグナルをepollで監視する。


signalfd.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/signalfd.h>
#include <errno.h>

#define MAX_EVENTS 10
#define RET_OK (0)
#define RET_NG (-1)

#define PERROR(X) \
{\
    char __strerr[128] = {0};\
    int errcode = errno;\
    \
    strerror_r(errcode, __strerr, sizeof(__strerr));\
    printf(X " failed(%d:%s)\n", errcode, __strerr);\
}

static int createSignalFd(int* sfd);
static int waitSignalEvent(int sfd);

int main(void)
{
    int sfd = -1;
    int ret = RET_OK;

    do {
        ret = createSignalFd(&sfd);
        if (RET_OK != ret) {
            printf("createSignalFd() failed(%d)\n", ret);
            break;
        }

        ret = waitSignalEvent(sfd);
        if (RET_OK != ret) {
            printf("waitSignalEvent");
            close(sfd);
            break;
        }

        close(sfd);
    } while(0);


    return 0;
}

static int createSignalFd(int* sfd)
{
    int ret = RET_OK;
    sigset_t    mask;

    sigemptyset(&mask);

    sigaddset(&mask, SIGHUP);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGQUIT);

    do {
        if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
            PERROR("sigprocmask()");
            break;
        }

        *sfd = signalfd(-1, &mask, 0);
        if (*sfd < 0) {
            PERROR("signalfd()");
            ret = RET_NG;
            break;
        }
    } while(0);

    return ret;
}

static int waitSignalEvent(int sfd)
{
    int ret = RET_OK;
    int rc = 0;
    int epollfd = -1;
    int nfds = -1;
    struct epoll_event events[MAX_EVENTS];
    struct epoll_event evt = {
        .events = EPOLLIN,
        .data = {
            .fd = sfd,
        },
    };

    epollfd = epoll_create(MAX_EVENTS);
    if (epollfd < 0) {
        PERROR("epoll_create()");
        goto error_end;
    }

    rc = epoll_ctl(epollfd, EPOLL_CTL_ADD, sfd, &evt);
    if (rc != 0) {
        PERROR("epoll_ctl()");
        close(epollfd);
        goto error_end;
    }

    for(;;) {
        nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        if (nfds < 0) {
            PERROR("epoll_wait()");
            close(epollfd);
            break;
        }

        int fd = 0;
        for (fd = 0; fd < MAX_EVENTS; fd++) {
            if (events[fd].data.fd == sfd) {
                struct signalfd_siginfo fdsi;
                ssize_t sz = read(sfd, &fdsi, sizeof(fdsi));
                if (sz < 0) {
                    PERROR("read()");
                    close(epollfd);
                    break;
                }

                printf("ssi_signo = %d\n", fdsi.ssi_signo);
            }
        }
    }

    close(epollfd);
error_end:

    return ret;
}


実行結果

$ gcc -std=gnu99 signalfd.c -o signalfd
$ ./signalfd
ssi_signo = 1
ssi_signo = 2
ssi_signo = 3
Terminated

#別端末から
$ killall -SIGHUP signalfd
$ killall -SIGINT signalfd
$ killall -SIGQUIT signalfd
$ killall -SIGTERM signalfd