#include <Conn_config.h>
#ifdef EPOLL_FOUND
#include <Conn_engine_epoll.h>
/*
* Variables
*/
static unsigned long Conn_epoll_allocated_slots = 0;
static int Conn_epoll_fd;
static struct epoll_event *Conn_epoll_events = NULL;
/*
* Functions
*/
/*
* Init the engine
*/
int Conn_epoll_init(void)
{
Conn_epoll_fd = epoll_create(256);
if (Conn_epoll_fd == -1) {
snprintf(Conn_error, sizeof(Conn_error),
"Cannot open epoll socket (%s).", strerror(errno));
return -1;
}
return 0;
}
int Conn_epoll_shutdown(void)
{
int ret;
free(Conn_epoll_events);
ret = close(Conn_epoll_fd);
if (ret != 0)
return -1;
return 0;
}
/*
* Grow the number of slots needed for epoll
*/
int Conn_epoll_grow(unsigned int alloc)
{
struct epoll_event *p, *set;
unsigned int diff;
Log(10, "%s: Try to grow pollfds from %d to %d.\n",
__FUNCTION__,
Conn_epoll_allocated_slots, alloc);
if (alloc <= Conn_epoll_allocated_slots)
return 0;
diff = alloc - Conn_epoll_allocated_slots;
p = (struct epoll_event *) realloc(Conn_epoll_events, alloc
* sizeof(struct epoll_event));
if (p == NULL) {
snprintf(Conn_error, sizeof(Conn_error),
"Cannot alloc memory for epoll_events.");
return -1;
}
set = p + Conn_epoll_allocated_slots;
memset(set, 0, diff * sizeof(struct epoll_event));
Conn_epoll_events = p;
return 0;
}
/*
* Add a target to the list
*/
int Conn_epoll_add_obj(struct Conn *C)
{
int ret;
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.data.ptr = (void *) C->slot;
ev.events = C->events;
ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_ADD, C->fd, &ev);
if (ret == -1) {
C->xerrno = errno;
snprintf(Conn_error, sizeof(Conn_error),
"Cannot add obj to list (%s).",
strerror(C->xerrno));
return C->xerrno;
}
return 0;
}
/*
* Remove a target from list
*/
int Conn_epoll_del_obj(struct Conn *C)
{
int ret;
ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_DEL, C->fd, NULL);
if (ret == -1) {
/* Counld not happen! */
Log(0, "chg_obj: Could not delete fd %d (%s). Bug!\n",
C->fd, strerror(errno));
abort();
}
return 0;
}
/*
* Change event mask
*/
int Conn_epoll_chg_obj(struct Conn *C)
{
struct epoll_event ev;
int ret;
/* We may move a slot already in error state */
if (C->fd == -1)
return 0;
memset(&ev, 0, sizeof(ev));
ev.events = C->events;
ev.data.ptr = (void *) C->slot;
ret = epoll_ctl(Conn_epoll_fd, EPOLL_CTL_MOD, C->fd, &ev);
if (ret != 0) {
/* Could not happen! */
Log(0, "chg_obj: Could not change fd %d (%s). Bug!\n",
C->fd, strerror(errno));
abort();
}
return 0;
}
/*
* Calls a callback for fds with activity
* Returns: -1 on error, 0 nothing to do, n (>0) if some work was done
* timeout is in 1/1000 seconds increments.
*/
int Conn_epoll_poll(const int timeout2, void (*cb)(struct Conn *C,
const int revents))
{
int i, events;
struct Conn *C;
unsigned int slot;
again:
events = epoll_wait(Conn_epoll_fd, Conn_epoll_events, Conn_no, timeout2);
if ((events == -1) && (errno == EINTR))
goto again;
if (events < 0) {
snprintf(Conn_error, sizeof(Conn_error),
"%s: Conn_no=%d [%s]",
__FUNCTION__, Conn_no, strerror(errno));
return -1;
}
gettimeofday(&Conn_now, NULL);
if (events == 0)
return 0;
Log(11, "Processing %d event(s)...\n", events);
i = events - 1;
do {
slot = (unsigned int) Conn_epoll_events[i].data.ptr;
C = &Conns[slot];
cb(C, Conn_epoll_events[i].events);
i--;
} while (i >= 0);
return events;
}
/*
* Move a slot over an other.
*/
int Conn_epoll_move_slot(const unsigned int dst, const unsigned int src)
{
/* Because slot was changed, update epoll info */
Conn_epoll_chg_obj(&Conns[dst]);
return 0;
}
#endif