about summary refs log tree commit diff
path: root/evloop/epoll.c
diff options
context:
space:
mode:
authorRichard Nyberg <rnyberg@murmeldjur.se>2009-01-09 18:26:23 +0100
committerRichard Nyberg <rnyberg@murmeldjur.se>2009-01-11 15:26:46 +0100
commit59905999ce145a81e0003766d468945c2444a90e (patch)
treeb4b2f566942c2a4b90ab7a6d6111c73c49e4afc5 /evloop/epoll.c
parent4457c1268a923d2a662ab23ca1b8d7920811ae51 (diff)
downloadbtpd-59905999ce145a81e0003766d468945c2444a90e.tar.gz
btpd-59905999ce145a81e0003766d468945c2444a90e.zip
Add evloop, btpd's new event loop. This will replace libevent.
Diffstat (limited to 'evloop/epoll.c')
-rw-r--r--evloop/epoll.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/evloop/epoll.c b/evloop/epoll.c
new file mode 100644
index 0000000..5152194
--- /dev/null
+++ b/evloop/epoll.c
@@ -0,0 +1,118 @@
+#include <sys/epoll.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "evloop.h"
+
+static int m_epfd;
+
+static struct epoll_event m_evs[100];
+static uint8_t m_valid[100];
+
+int
+evloop_init(void)
+{
+    if (timeheap_init() != 0)
+        return -1;
+    m_epfd = epoll_create(getdtablesize());
+    return m_epfd >= 0 ? 0 : -1;
+}
+
+int
+fdev_new(struct fdev *ev, int fd, uint16_t flags, evloop_cb_t cb, void *arg)
+{
+    ev->fd = fd;
+    ev->cb = cb;
+    ev->arg = arg;
+    ev->flags = 0;
+    ev->index = -1;
+    return fdev_enable(ev, flags);
+}
+
+int
+fdev_enable(struct fdev *ev, uint16_t flags)
+{
+    struct epoll_event epev;
+    int err = 0;
+    uint16_t sf = ev->flags;
+    ev->flags |= flags;
+    if (sf != ev->flags) {
+        epev.data.ptr = ev;
+        epev.events =
+            ((ev->flags & EV_READ) ? EPOLLIN : 0) |
+            ((ev->flags & EV_WRITE) ? EPOLLOUT : 0);
+        if (sf == 0)
+            err = epoll_ctl(m_epfd, EPOLL_CTL_ADD, ev->fd, &epev);
+        else
+            err = epoll_ctl(m_epfd, EPOLL_CTL_MOD, ev->fd, &epev);
+    }
+    return err;
+}
+
+int
+fdev_disable(struct fdev *ev, uint16_t flags)
+{
+    struct epoll_event epev;
+    int err = 0;
+    uint16_t sf = ev->flags;
+    ev->flags &= ~flags;
+    if (sf != ev->flags) {
+        epev.data.ptr = ev;
+        epev.events =
+            ((ev->flags & EV_READ) ? EPOLLIN : 0) |
+            ((ev->flags & EV_WRITE) ? EPOLLOUT : 0);
+        if (ev->flags == 0)
+            err = epoll_ctl(m_epfd, EPOLL_CTL_DEL, ev->fd, &epev);
+        else
+            err = epoll_ctl(m_epfd, EPOLL_CTL_MOD, ev->fd, &epev);
+    }
+    return err;
+}
+
+int
+fdev_del(struct fdev *ev)
+{
+    if (ev->index >= 0)
+        m_valid[ev->index] = 0;
+    return fdev_disable(ev, EV_READ|EV_WRITE);
+}
+
+int
+evloop(void)
+{
+    int nev, i, millisecs;
+    struct timespec delay;
+    while (1) {
+        timers_run();
+        delay = timer_delay();
+        if (delay.tv_sec >= 0)
+            millisecs = delay.tv_sec * 1000 + delay.tv_nsec / 1000000;
+        else
+            millisecs = -1;
+
+        if ((nev = epoll_wait(m_epfd, m_evs, 100, millisecs)) < 0) {
+            if (errno == EINTR)
+                continue;
+            else
+                return -1;
+        }
+        memset(m_valid, 1, nev);
+        for (i = 0; i < nev; i++) {
+            struct fdev *ev = m_evs[i].data.ptr;
+            ev->index = i;
+        }
+        for (i = 0; i < nev; i++) {
+            struct fdev *ev = m_evs[i].data.ptr;
+            if ((m_valid[i] &&
+                    ev->flags & EV_READ &&
+                    m_evs[i].events & (EPOLLIN|EPOLLERR|EPOLLHUP)))
+                ev->cb(ev->fd, EV_READ, ev->arg);
+            if ((m_valid[i] && ev->flags & EV_WRITE &&
+                    m_evs[i].events & (EPOLLOUT|EPOLLERR|EPOLLHUP)))
+                ev->cb(ev->fd, EV_WRITE, ev->arg);
+            if (m_valid[i])
+                ev->index = -1;
+        }
+    }
+}