Created
March 15, 2014 16:50
-
-
Save dsheeler/9570290 to your computer and use it in GitHub Desktop.
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 <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