Skip to content

Instantly share code, notes, and snippets.

@dsheeler
Created March 15, 2014 01:29
Show Gist options
  • Save dsheeler/9560509 to your computer and use it in GitHub Desktop.
Save dsheeler/9560509 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/signalfd.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <errno.h>
#define KR_EPOLL_MAX_EVENTS 10
static void handle_error(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
int kr_setup_signalfd() {
sigset_t mask;
int sfd;
int flags;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
sigaddset(&mask, SIGTERM);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
handle_error("sigprocmask");
}
flags = SFD_NONBLOCK | SFD_CLOEXEC;
sfd = signalfd(-1, &mask, flags);
if (sfd == 1) {
handle_error("signalfd");
}
return sfd;
}
void set_nonblocking_cloexec(int fd) {
int flags;
flags = fcntl(fd, F_GETFD);
if (flags == -1) {
handle_error("fcntl F_GETFD");
}
flags |= O_CLOEXEC | O_NONBLOCK;
if (fcntl(fd, F_SETFD, flags) == -1) {
handle_error("fcntl F_SETFD");
}
}
void epoll_add_fd(int epollfd, int fd) {
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = fd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
handle_error("epoll_ctl");
}
}
int kr_setup_epollfd() {
int epollfd;
epollfd = epoll_create(KR_EPOLL_MAX_EVENTS);
if (epollfd == -1) {
handle_error("epoll_create");
}
set_nonblocking_cloexec(epollfd);
return epollfd;
}
int process_signal_event(struct epoll_event *event) {
struct signalfd_siginfo sig_info;
int sig_size = sizeof(struct signalfd_siginfo);
int to_read = sig_size;
ssize_t did_read;
int count = 0;
while (1) {
did_read = read(event->data.fd, &sig_info, to_read);
if (did_read == -1) {
if (errno != EAGAIN) {
handle_error("signal read");
}
break;
}
if (did_read < to_read) {
to_read -= did_read;
continue; }
to_read = sig_size;
++count;
if (sig_info.ssi_signo == SIGINT) {
printf("Got SIGINT\n");
} else if (sig_info.ssi_signo == SIGTERM) {
printf("Got SIGTERM\n");
} else {
printf("Got unexpected signal\n");
}
}
return count;}
static void print_elapsed_time(void) {
static struct timespec start;
struct timespec curr;
static int first_call = 1;
int secs, nsecs;
if (first_call) {
first_call = 0;
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
handle_error("clock_gettime");
}
if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
handle_error("clock_gettime");
secs = curr.tv_sec - start.tv_sec;
nsecs = curr.tv_nsec - start.tv_nsec;
if (nsecs < 0) {
secs--;
nsecs += 1000000000;
}
printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);
}
int main(int argc, char **argv) {
int epollfd;
struct epoll_event events[KR_EPOLL_MAX_EVENTS];
int sfd;
struct itimerspec new_value;
int tfd;
int flags;
int nfds, n;
int done = 0; int exp = 0;
int max_exp = 5;
epollfd = kr_setup_epollfd();
sfd = kr_setup_signalfd();
epoll_add_fd(epollfd, sfd);
new_value.it_value.tv_sec = 1;
new_value.it_value.tv_nsec = 0;
new_value.it_interval.tv_sec = 1;
new_value.it_interval.tv_nsec = 0;
flags = TFD_NONBLOCK | TFD_CLOEXEC;
tfd = timerfd_create(CLOCK_MONOTONIC, flags);
if (tfd == -1) {
handle_error("timerfd_create");
}
if (timerfd_settime(tfd, 0, &new_value, NULL) == -1) {
handle_error("timerfd_settime");
}
epoll_add_fd(epollfd, tfd);
print_elapsed_time();
printf("Starting timer!\n");
while (done == 0) {
nfds = epoll_wait(epollfd, events, KR_EPOLL_MAX_EVENTS, -1);
if (nfds == -1) {
handle_error("epoll_pwait");
}
for (n = 0; n < nfds; n++) {
if (events[n].data.fd == sfd) {
process_signal_event(&events[n]);
} else if (events[n].data.fd == tfd) {
print_elapsed_time();
printf("Interval %d\n", exp);
if (++exp == max_exp) {
done = 1;
printf("Times up! Goodbye.\n");
}
}
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment