Skip to content

Instantly share code, notes, and snippets.

@dsheeler
Created March 15, 2014 16:50
Show Gist options
  • Save dsheeler/9570290 to your computer and use it in GitHub Desktop.
Save dsheeler/9570290 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/signalfd.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#define KR_EPOLL_MAX_EVENTS 10
#define KR_POPEN_BUF_SIZE 8192
static void handle_error(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
static int kr_setup_signalfd() {
sigset_t mask;
int sfd;
int flags;
sigemptyset(&mask);
sigfillset(&mask);
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;
}
static void epoll_add_fd(int epollfd, int fd) {
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = fd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
handle_error("epoll_ctl");
}
}
static int kr_setup_epollfd() {
int epollfd;
epollfd = epoll_create1(EPOLL_CLOEXEC);
if (epollfd == -1) {
handle_error("epoll_create");
}
return epollfd;
}
static 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;
for (;;) {
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 a 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);
}
static int kr_setup_timerfd() {
struct itimerspec new_value;
int tfd;
int flags;
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");
}
return tfd;
}
static void process_timerfd_event(int tfd) {
uint64_t nexp;
int ret;
struct itimerspec timer_time;
nexp = 0;
ret = read(tfd, &nexp, sizeof(nexp));
if (ret == -1) {
perror("read timerfd");
}
printf("Timer expired\n");
ret = timerfd_gettime(tfd, &timer_time);
if (ret == -1) {
perror("timerfd_gettime");
}
}
static FILE *launch_get_media_info(const char *url) {
FILE *fp;
char cmd[512];
/*snprintf(cmd, 512, "kr_quvi_test %s", url);*/
snprintf(cmd, 512, "ls");
cmd[511] = '\0';
fp = popen("ls", "r");
if (fp == NULL) {
handle_error("dang popen failed\n");
}
return fp;
}
static void process_popen_event(struct epoll_event *event) {
char output[KR_POPEN_BUF_SIZE];
int to_read = KR_POPEN_BUF_SIZE;
ssize_t did_read;
if (event->events & EPOLLIN) {
printf("Got EPOLLIN\n");
} else if (event->events & EPOLLERR) {
printf("Got EPOLLERR\n");
} else if (event->events & EPOLLHUP) {
printf("Got EPOLLHUP\n");
} else {
printf("Got other EPOLL event\n");
}
for (;;) {
did_read = read(event->data.fd, output, to_read);
printf("wft %d\n", did_read);
if ((did_read == 0) || (did_read == -1)) {
break;
}
fprintf(stdout, "%s", output);
}
}
int main(int argc, char **argv) {
int epollfd;
struct epoll_event events[KR_EPOLL_MAX_EVENTS];
int nfds, n;
int sfd;
int tfd;
int done = 0;
int exp = 0;
int max_exp = 20;
FILE *quvi_proc;
int qfd;
epollfd = kr_setup_epollfd();
sfd = kr_setup_signalfd();
epoll_add_fd(epollfd, sfd);
tfd = kr_setup_timerfd();
epoll_add_fd(epollfd, tfd);
print_elapsed_time();
printf("Starting timer!\n");
quvi_proc = launch_get_media_info("https://www.youtube.com/watch?v=DBNy4WVm3D4");
qfd = fileno(quvi_proc);
epoll_add_fd(epollfd, qfd);
while (!done) {
nfds = epoll_wait(epollfd, events, KR_EPOLL_MAX_EVENTS, -1);
if (nfds == -1) {
handle_error("epoll_pwait");
}
print_elapsed_time();
printf("Mainloop got %d events!\n", nfds);
for (n = 0; n < nfds; n++) {
if (events[n].data.fd == sfd) {
process_signal_event(&events[n]);
} else if (events[n].data.fd == tfd) {
process_timerfd_event(tfd);
++exp;
if (exp == max_exp) {
done = 1;
}
} else {
process_popen_event(&events[n]);
}
}
}
printf("Times up! Goodbye.\n");
/* lets close things */
if (close(tfd)) {
perror("close tfd");
}
if (close(epollfd)) {
perror("close epollfd");
}
if (close(sfd)) {
perror("close sfd");
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment