diff options
| author | Richard Nyberg <rnyberg@murmeldjur.se> | 2009-01-09 18:26:23 +0100 |
|---|---|---|
| committer | Richard Nyberg <rnyberg@murmeldjur.se> | 2009-01-11 15:26:46 +0100 |
| commit | 59905999ce145a81e0003766d468945c2444a90e (patch) | |
| tree | b4b2f566942c2a4b90ab7a6d6111c73c49e4afc5 /evloop/epoll.c | |
| parent | 4457c1268a923d2a662ab23ca1b8d7920811ae51 (diff) | |
| download | btpd-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.c | 118 |
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; + } + } +} |