Skip to content

Instantly share code, notes, and snippets.

@tetsu-koba
Created December 17, 2022 02:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tetsu-koba/bc9ccf2103310f61252e0f32785cc7e3 to your computer and use it in GitHub Desktop.
Save tetsu-koba/bc9ccf2103310f61252e0f32785cc7e3 to your computer and use it in GitHub Desktop.
epoll and signalfd example in C
#include <stdio.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/signalfd.h>
#define MAX_EVENTS 5
#define READ_BUFSIZE (64*1024)
#define WRITE_BUFSIZE (64*1024)
int create_signalfd(void)
{
sigset_t mask;
sigemptyset (&mask);
sigaddset (&mask, SIGINT);
sigaddset (&mask, SIGTERM);
sigaddset (&mask, SIGUSR1);
sigaddset (&mask, SIGUSR2);
sigprocmask (SIG_BLOCK, &mask, NULL);
return signalfd (-1, &mask, SFD_CLOEXEC);
}
int write_full(int fd, char *buf, int len)
{
int written = 0;
int n;
while (written < len) {
n = write(fd, buf + written, len - written);
if (n < 0 && errno != EINTR) {
return n;
}
written += n;
}
return written;
}
int nop_filter(char *rbuf, int rlen, char *wbuf, int wlen)
{
// Just copy now. replace this to do something
memcpy(wbuf, rbuf, rlen);
return rlen;
}
int pipe_loop(int timeout, int verbose)
{
int running = 1, event_count, i;
size_t bytes_read;
struct epoll_event event, events[MAX_EVENTS];
int epoll_fd, signal_fd;
char read_buffer[READ_BUFSIZE];
char write_buffer[READ_BUFSIZE];
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
fprintf(stderr, "Failed to create epoll file descriptor\n");
return 1;
}
event.events = EPOLLIN;
event.data.fd = STDIN_FILENO;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event.data.fd, &event)){
fprintf(stderr, "Failed to add file descriptor to epoll:%s\n", strerror(errno));
close(epoll_fd);
return 1;
}
signal_fd = create_signalfd();
if (signal_fd == -1) {
fprintf(stderr, "Failed to create signal file descriptor\n");
return 1;
}
event.events = EPOLLIN;
event.data.fd = signal_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event.data.fd, &event)){
fprintf(stderr, "Failed to add signal file descriptor to epoll\n");
close(epoll_fd);
return 1;
}
while (running) {
event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout);
if (0 == event_count) {
fprintf(stderr, "timeout\n");
}
for (i = 0; i < event_count; i++) {
if (events[i].data.fd == STDIN_FILENO) {
bytes_read = read(events[i].data.fd, read_buffer, READ_BUFSIZE);
if (verbose) {
fprintf(stderr, "bytes_read=%ld\n", bytes_read);
}
if (bytes_read == 0) { // EOF?
running = 0;
} else if (bytes_read < 0 && errno != EINTR) {
fprintf(stderr, "read:%s\n", strerror(errno));
running = 0;
} else {
int n = nop_filter(read_buffer, bytes_read, write_buffer, sizeof write_buffer);
if (n < 0) {
running = 0;
}
if (write_full(STDOUT_FILENO, write_buffer, n) < 0) {
fprintf(stderr, "write:%s\n", strerror(errno));
running = 0;
}
}
} else if (events[i].data.fd == signal_fd) {
struct signalfd_siginfo info = {0};
read (signal_fd, &info, sizeof(info));
switch (info.ssi_signo) {
case SIGINT:
fprintf(stderr, "Got SIGINT\n");
running = 0;
break;
case SIGTERM:
fprintf(stderr, "Got SIGTERM\n");
running = 0;
break;
case SIGUSR1:
fprintf(stderr, "Set verbose=0\n");
verbose = 0;
break;
case SIGUSR2:
fprintf(stderr, "Set verbose=1\n");
verbose = 1;
break;
default:
fprintf(stderr, "Got signal %d\n", info.ssi_signo);
running = 0;
break;
}
} else {
fprintf(stderr, "unknown fd: %d", events[i].data.fd);
return 1;
}
}
}
if (close(epoll_fd)) {
fprintf(stderr, "Failed to close epoll file descriptor\n");
return 1;
}
return 0;
}
int main(int argc, char **argv)
{
int timeout = 10 * 1000;
int verbose = 1;
return(pipe_loop(timeout, verbose));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment