summaryrefslogtreecommitdiff
path: root/epoll.c
diff options
context:
space:
mode:
authorSøren Sandmann <sandmann@redhat.com>2009-04-02 14:00:18 -0400
committerSøren Sandmann <sandmann@redhat.com>2009-04-02 14:00:18 -0400
commit98a8963ee6c5c38a19cfd23dcd596b8b5e09a348 (patch)
treed4a50d70a43ac22d1cdf5020f47c9d2f12e344b4 /epoll.c
parent72813fba0400d4b8abf370fded95b0d7164e08b8 (diff)
Add epoll.[ch]
Diffstat (limited to 'epoll.c')
-rw-r--r--epoll.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/epoll.c b/epoll.c
new file mode 100644
index 0000000..a464cc7
--- /dev/null
+++ b/epoll.c
@@ -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;
+}