シグナル受信を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
コメント