Created
December 17, 2022 02:45
-
-
Save tetsu-koba/bc9ccf2103310f61252e0f32785cc7e3 to your computer and use it in GitHub Desktop.
epoll and signalfd example in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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