Created
May 19, 2012 03:01
-
-
Save maxdeliso/2728793 to your computer and use it in GitHub Desktop.
epolltest.c
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
/* | |
* author: Max DeLiso <[email protected]> | |
* file: epolltest.c | |
* description: some experiments with polling | |
* stdin and signalfd on linux | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <sys/epoll.h> | |
#include <sys/signalfd.h> | |
#include <assert.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <curses.h> | |
#include <stdbool.h> | |
#include <ctype.h> | |
static const int MAX_EVENTS = 64; | |
static const int EV_TIMEOUT = 100; | |
int registerSigHandler(int epfd); | |
void registerStdin(int epfd); | |
void allocateResources(); | |
void deallocateResources(); | |
void evLoop(int epfd, int sfd, struct epoll_event *evBuffer); | |
int main() | |
{ | |
static int epfd; | |
static int sfd; | |
static struct epoll_event *evBuffer = NULL; | |
initscr(); | |
cbreak(); | |
noecho(); | |
wprintw(stdscr, "epolltest - q quits\n"); | |
refresh(); | |
allocateResources(&epfd, &evBuffer); | |
sfd = registerSigHandler(epfd); | |
registerStdin(epfd); | |
evLoop(epfd, sfd, evBuffer); | |
deallocateResources(epfd, sfd, evBuffer); | |
endwin(); | |
return EXIT_SUCCESS; | |
} | |
int registerSigHandler(int epfd) | |
{ | |
auto int sfd; | |
auto sigset_t mask; | |
/* initialize requisite data structures */ | |
sigfillset(&mask); | |
/* check block all default signal handlers */ | |
if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { | |
perror("sigprocmask"); | |
exit(EXIT_FAILURE); | |
} | |
/* register all possible signals to the signalfd */ | |
sfd = signalfd(-1, &mask, 0); | |
if (sfd < 0) { | |
perror("signalfd"); | |
exit(EXIT_FAILURE); | |
} | |
/* initialize the signalfd to the event struct */ | |
struct epoll_event signalEvent = { | |
.events = EPOLLIN | EPOLLPRI, | |
.data.fd = sfd | |
}; | |
/* register the signalfd with the event structure */ | |
if (epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &signalEvent) < 0) { | |
perror("epoll_ctl"); | |
exit(EXIT_FAILURE); | |
} | |
return sfd; | |
} | |
void registerStdin(int epfd) | |
{ | |
/* epoll data */ | |
auto struct epoll_event stdinEvent = { | |
.events = EPOLLIN | EPOLLPRI, | |
.data.fd = STDIN_FILENO | |
}; | |
/* register stdin and signal fd to the event handler */ | |
if ((epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &stdinEvent) < 0)) { | |
perror("epoll_ctl"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
void allocateResources(int *epfdPtr, struct epoll_event **evBufferPtr) | |
{ | |
/* allocate space off the heap for the event buffer */ | |
if (((*evBufferPtr) = | |
malloc(sizeof(struct epoll_event) * MAX_EVENTS)) == NULL) { | |
perror("malloc"); | |
exit(EXIT_FAILURE); | |
} | |
/* register backing store for event processing */ | |
if (((*epfdPtr) = epoll_create(1)) < 0) { | |
perror("epoll_create"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
void deallocateResources(int epfd, int sfd, struct epoll_event *evBuffer) | |
{ | |
/* close the file descriptors */ | |
if (close(epfd) < 0 || close(sfd) < 0) { | |
perror("close"); | |
} | |
/* return the event buffer to the heap */ | |
free(evBuffer); | |
} | |
void evLoop(int epfd, int sfd, struct epoll_event *evBuffer) | |
{ | |
auto int signalCount = 0; | |
auto int inputCount = 0; | |
auto int timeoutCount = 0; | |
auto bool alive; | |
static const int inputRow = 1; | |
static const int signalRow = 2; | |
static const int timeoutRow = 3; | |
static const int errorRow = 4; | |
mvwprintw(stdscr, inputRow, 0, "inputs: %i\n", inputCount); | |
mvwprintw(stdscr, signalRow, 0, "signals: %i\n", signalCount); | |
mvwprintw(stdscr, timeoutRow, 0, "timeouts: %i\n", timeoutCount); | |
refresh(); | |
alive = true; | |
for (int eret; | |
alive && | |
((eret = epoll_wait(epfd, evBuffer, MAX_EVENTS, EV_TIMEOUT)) >= 0);) { | |
if (eret == 0) { | |
++timeoutCount; | |
mvwprintw(stdscr, timeoutRow, 0, "timeouts: %i\n", timeoutCount); | |
/* TODO: idle processing */ | |
} else | |
for (int i = 0; i < eret; ++i) { | |
const int cfd = evBuffer[i].data.fd; | |
auto char userChar; | |
if (cfd == STDIN_FILENO) { | |
if ( (userChar = wgetch(stdscr)) == ERR) { | |
mvwprintw(stdscr, errorRow, 0, "wgetch failed"); | |
} else { | |
++inputCount; | |
mvwprintw(stdscr, inputRow, 0, "inputs: %i\n", inputCount); | |
if( tolower(userChar) == 'q') { | |
alive = false; | |
} | |
/* TODO: handle user input */ | |
} | |
} else if (cfd == sfd) { | |
auto struct signalfd_siginfo fdsi; | |
if (read(sfd, | |
&fdsi, | |
sizeof(struct signalfd_siginfo)) != | |
sizeof(struct signalfd_siginfo)) { | |
mvwprintw(stdscr, | |
errorRow, | |
0, "read() failed: %s\n", strerror(errno)); | |
} else { | |
++signalCount; | |
mvwprintw(stdscr, | |
signalRow, 0, | |
"signals: %i\n", signalCount); | |
/* TODO: report signal info */ | |
} | |
} else { | |
mvwprintw(stdscr, 6, 0, "unhandled event\n", i); | |
} | |
/* place the cursor below the output text - for kill handler */ | |
mvcur(getcurx(stdscr), getcury(stdscr), errorRow, 0); | |
} /* for */ | |
/* flush to screen */ | |
refresh(); | |
} /* for */ | |
} |
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
CFLAGS=-std=c99 -pedantic -Wall -Wextra \ | |
-D_POSIX_SOURCE -g -O3 | |
RM=rm | |
SRC=epolltest | |
CC=gcc | |
LDFLAGS=-lncurses | |
$(SRC): $(SRC).o makefile | |
$(CC) $(CFLAGS) $(LDFLAGS) $(SRC).o -o $(SRC) | |
$(SRC).o: $(SRC).c makefile | |
$(CC) $(CFLAGS) $(SRC).c -c -o $(SRC).o | |
clean: | |
$(RM) -f $(SRC) $(SRC).o |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment