Skip to content

Instantly share code, notes, and snippets.

@maxdeliso
Created May 19, 2012 03:01
Show Gist options
  • Save maxdeliso/2728793 to your computer and use it in GitHub Desktop.
Save maxdeliso/2728793 to your computer and use it in GitHub Desktop.
epolltest.c
/*
* author: Max DeLiso <maxdeliso@gmail.com>
* 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 */
}
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