Skip to content

Instantly share code, notes, and snippets.

@edef1c
Last active August 13, 2019 03:42
Show Gist options
  • Save edef1c/db1e6b3e44d7d3b4ad20241e0bb532aa to your computer and use it in GitHub Desktop.
Save edef1c/db1e6b3e44d7d3b4ad20241e0bb532aa to your computer and use it in GitHub Desktop.
proof-of-concept of siglongjmp/ppoll-based signal handling in an event loop
#define _GNU_SOURCE
#include <err.h>
#include <errno.h>
#include <poll.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static sigjmp_buf sig_buf;
static void sig_handler(int signo) {
siglongjmp(sig_buf, signo);
}
int main(void) {
sigset_t jesus, blocked; // none of you are free of sin
sigemptyset(&blocked);
sigaddset(&blocked, SIGINT);
sigprocmask(SIG_BLOCK, &blocked, &jesus);
int signo = sigsetjmp(sig_buf, 1);
if (signo) {
printf("caught signal %d\n", signo);
} else if (sigaction(SIGINT, &(struct sigaction) { .sa_handler = sig_handler }, NULL)) {
err(1, "signal");
}
struct pollfd pfd = {
.fd = 0,
.events = POLLIN
};
for (;;) {
int ret = ppoll(&pfd, 1, NULL, signo ? NULL : &jesus);
if (ret < 0) err(1, "ppoll");
signo = 0;
if (pfd.revents & (POLLIN | POLLERR)) {
char buffer[32];
int n;
do { n = read(pfd.fd, buffer, sizeof buffer); }
while (n < 0 && (errno == EAGAIN || errno == EINTR));
if (n < 0) err(1, "read");
write(1, buffer, n); // XXX: check the return value
} else if (pfd.revents & POLLHUP) {
break;
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment