diff options
author | Søren Sandmann <sandmann@redhat.com> | 2009-04-02 14:00:18 -0400 |
---|---|---|
committer | Søren Sandmann <sandmann@redhat.com> | 2009-04-02 14:00:18 -0400 |
commit | 98a8963ee6c5c38a19cfd23dcd596b8b5e09a348 (patch) | |
tree | d4a50d70a43ac22d1cdf5020f47c9d2f12e344b4 /epoll.c | |
parent | 72813fba0400d4b8abf370fded95b0d7164e08b8 (diff) |
Add epoll.[ch]
Diffstat (limited to 'epoll.c')
-rw-r--r-- | epoll.c | 192 |
1 files changed, 192 insertions, 0 deletions
@@ -0,0 +1,192 @@ +#include "epoll.h" +#include <sys/poll.h> + +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; +} |