Created
March 15, 2014 01:29
-
-
Save dsheeler/9560509 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 <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