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/poll.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/poll.c')
| -rw-r--r-- | evloop/poll.c | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/evloop/poll.c b/evloop/poll.c new file mode 100644 index 0000000..0996374 --- /dev/null +++ b/evloop/poll.c @@ -0,0 +1,142 @@ +#include <assert.h> +#include <errno.h> +#include <poll.h> +#include <stdlib.h> +#include <string.h> + +#include "evloop.h" + +#define POLL_INIT_SIZE 64 + +struct poll_ev { + struct fdev *ev; + evloop_cb_t cb; + void *arg; +}; + +static struct pollfd *m_pfds; +static struct poll_ev *m_pevs; + +static int m_cap, m_size; +static int m_cur = -1, m_curdel; + +static int +poll_grow(void) +{ + int ncap = m_cap * 2; + struct pollfd *nm_pfds = realloc(m_pfds, ncap * sizeof(*m_pfds)); + struct poll_ev *nm_pevs = realloc(m_pevs, ncap * sizeof(*m_pevs)); + if (nm_pfds != NULL) + m_pfds = nm_pfds; + if (nm_pevs != NULL) + m_pevs = nm_pevs; + if (nm_pfds == NULL || nm_pevs == NULL) + return errno; + m_cap = ncap; + return 0; +} + +int +evloop_init(void) +{ + if (timeheap_init() != 0) + return -1; + m_cap = POLL_INIT_SIZE; + m_size = 0; + if ((m_pfds = calloc(m_cap, sizeof(*m_pfds))) == NULL) + return -1; + if ((m_pevs = calloc(m_cap, sizeof(*m_pevs))) == NULL) { + free(m_pfds); + return -1; + } + return 0; +} + +int +fdev_new(struct fdev *ev, int fd, uint16_t flags, evloop_cb_t cb, void *arg) +{ + if (m_size == m_cap && poll_grow() != 0) + return errno; + ev->i = m_size; + m_size++; + m_pfds[ev->i].fd = fd; + m_pfds[ev->i].events = + ((flags & EV_READ) ? POLLIN : 0) | + ((flags & EV_WRITE) ? POLLOUT : 0); + m_pevs[ev->i].ev = ev; + m_pevs[ev->i].cb = cb; + m_pevs[ev->i].arg = arg; + return 0; +} + +int +fdev_enable(struct fdev *ev, uint16_t flags) +{ + m_pfds[ev->i].events |= + ((flags & EV_READ) ? POLLIN : 0) | + ((flags & EV_WRITE) ? POLLOUT : 0); + return 0; +} + +int +fdev_disable(struct fdev *ev, uint16_t flags) +{ + short pflags = + ((flags & EV_READ) ? POLLIN : 0) | + ((flags & EV_WRITE) ? POLLOUT : 0); + m_pfds[ev->i].events &= ~pflags; + return 0; +} + +int +fdev_del(struct fdev *ev) +{ + assert(ev->i < m_size); + m_size--; + m_pfds[ev->i] = m_pfds[m_size]; + m_pevs[ev->i] = m_pevs[m_size]; + m_pevs[ev->i].ev->i = ev->i; + if (ev->i == m_cur) + m_curdel = 1; + return 0; +} + +int +evloop(void) +{ + int 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 (poll(m_pfds, m_size, millisecs) < 0) { + if (errno == EINTR) + continue; + else + return -1; + } + + m_cur = 0; + while (m_cur < m_size) { + struct pollfd *pfd = &m_pfds[m_cur]; + struct poll_ev *pev = &m_pevs[m_cur]; + if ((pfd->events & POLLIN && + pfd->revents & (POLLIN|POLLERR|POLLHUP))) + pev->cb(pfd->fd, EV_READ, pev->arg); + if ((!m_curdel && pfd->events & POLLOUT && + pfd->revents & (POLLOUT|POLLERR|POLLHUP))) + pev->cb(pfd->fd, EV_WRITE, pev->arg); + if (!m_curdel) + m_cur++; + else + m_curdel = 0; + } + m_cur = -1; + } +} |