#include "epoll.h" #include typedef struct FdInfo FdInfo; struct FdInfo { /* FIXME: we might want to compress this struct at some point. * Though, if we have 100000 fd's, it's only 1.6 MB, which is * almost nothing for that many clients, Still, cache use * would improve. */ gboolean valid; gboolean disabled; EPollEventType mask; gpointer data; }; struct EPoll { int n_fds; gsize n_fd_infos; FdInfo * fd_info; }; EPoll * epoll_new (void) { EPoll *epoll = g_new0 (EPoll, 1); epoll->n_fds = 0; epoll->n_fd_infos = 1; epoll->fd_info = g_new0 (FdInfo, 1); return epoll; } void epoll_add_fd (EPoll *epoll, int fd, EPollEventType mask, gpointer data) { g_return_if_fail (!epoll_has_fd (epoll, fd)); while (fd >= epoll->n_fd_infos) epoll->n_fd_infos *= 2; epoll->fd_info = g_renew (FdInfo, epoll->fd_info, epoll->n_fd_infos); epoll->n_fds++; epoll->fd_info[fd].valid = TRUE; epoll->fd_info[fd].mask = mask; epoll->fd_info[fd].data = data; } gboolean epoll_has_fd (EPoll *epoll, int fd) { g_return_val_if_fail (epoll != NULL, FALSE); return (fd < epoll->n_fd_infos && epoll->fd_info[fd].valid); } gint epoll_get_n_fds (EPoll *epoll) { return epoll->n_fds; } void epoll_remove_fd (EPoll *epoll, int fd) { g_return_if_fail (epoll_has_fd (epoll, fd)); epoll->fd_info[fd].valid = FALSE; } gpointer epoll_get_fd_data (EPoll *epoll, int fd) { g_return_val_if_fail (epoll != NULL, NULL); g_return_val_if_fail (epoll_has_fd (epoll, fd), NULL); return epoll->fd_info[fd].data; } /* epoll_wait() is a one-shot polling mechanism, so this function * must be called to reenable fd's after they have been returned * by epoll_wait(). */ void epoll_reenable_fd (EPoll *epoll, int fd) { g_return_if_fail (epoll_has_fd (epoll, fd)); epoll->fd_info[fd].disabled = FALSE; } EPollEvent * epoll_wait (EPoll *epoll, int *n_events, int timeout) { struct pollfd *fds; int i, j; int n_poll_fds; int n_ready; EPollEvent *events; fds = g_new (struct pollfd, epoll->n_fds); j = 0; for (i = 0; i < epoll->n_fd_infos; ++i) { if (epoll->fd_info[i].valid && !epoll->fd_info[i].disabled && epoll->fd_info[i].mask != 0) { fds[j].events = 0; if (epoll->fd_info[i].mask & EPOLL_READ) fds[j].events |= POLLIN; if (epoll->fd_info[i].mask & EPOLL_WRITE) fds[j].events |= POLLOUT; if (epoll->fd_info[i].mask & EPOLL_HANGUP) fds[j].events |= POLLHUP; if (epoll->fd_info[i].mask & EPOLL_PRIORITY) fds[j].events |= POLLPRI; if (epoll->fd_info[i].mask & EPOLL_ERROR) fds[j].events |= POLLERR; fds[j].fd = i; j++; } } n_poll_fds = j; events = NULL; n_ready = poll (fds, n_poll_fds, timeout); if (n_ready) { events = g_new0 (EPollEvent, n_ready); j = 0; for (i = 0; i < n_poll_fds; ++i) { if (fds[i].revents) { events[j].events = 0; if (fds[i].revents & POLLIN) events[j].events |= EPOLL_READ; if (fds[i].revents & POLLOUT) events[j].events |= EPOLL_WRITE; if (fds[i].revents & POLLHUP) events[j].events |= EPOLL_HANGUP; if (fds[i].revents & POLLERR) events[j].events |= EPOLL_ERROR; if (fds[i].revents & POLLPRI) events[j].events |= EPOLL_PRIORITY; events[j].fd = fds[i].fd; epoll->fd_info[fds[i].fd].disabled = TRUE; } } } g_free (fds); if (n_events) *n_events = n_ready; return events; }