* SUCH DAMAGE.
*/
-#if (defined(__unix__) || defined(unix)) && !defined(USG)
-#include <sys/param.h>
-#endif
#include <sys/time.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
+#include <poll.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-/* config.h should define HAVE_KQUEUE, HAVE_EPOLL, etc. */
+/* config.h should define HAVE_PPOLL, etc. */
#if defined(HAVE_CONFIG_H) && !defined(NO_CONFIG_H)
#include "config.h"
#endif
-/* Attempt to autodetect kqueue or epoll.
- * Failing that, fall back to pselect. */
-#if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL) && !defined(HAVE_PSELECT) && \
- !defined(HAVE_POLLTS) && !defined(HAVE_PPOLL)
-#if defined(BSD)
-/* Assume BSD has a working sys/queue.h and kqueue(2) interface. */
-#define HAVE_SYS_QUEUE_H
-#define HAVE_KQUEUE
-#define WARN_SELECT
-#elif defined(__linux__) || defined(__sun)
-/* Assume Linux and Solaris have a working epoll(3) interface. */
-#define HAVE_EPOLL
-#define WARN_SELECT
-#else
-/* pselect(2) is a POSIX standard. */
+#if defined(HAVE_PPOLL)
+#elif defined(HAVE_POLLTS)
+#define ppoll pollts
+#elif !defined(HAVE_PSELECT)
+#pragma message("Compiling eloop with pselect(2) support.")
#define HAVE_PSELECT
-#define WARN_SELECT
-#endif
-#endif
-
-/* pollts and ppoll require poll.
- * pselect is wrapped in a pollts/ppoll style interface
- * and as such require poll as well. */
-#if defined(HAVE_PSELECT) || defined(HAVE_POLLTS) || defined(HAVE_PPOLL)
-#ifndef HAVE_POLL
-#define HAVE_POLL
-#endif
-#if defined(HAVE_POLLTS)
-#define POLLTS pollts
-#elif defined(HAVE_PPOLL)
-#define POLLTS ppoll
-#else
-#define POLLTS eloop_pollts
-#define ELOOP_NEED_POLLTS
-#endif
+#define ppoll eloop_ppoll
#endif
#include "eloop.h"
#endif
#endif
-#if defined(HAVE_KQUEUE)
-#include <sys/event.h>
-#include <fcntl.h>
-#ifdef __NetBSD__
-/* udata is void * except on NetBSD.
- * lengths are int except on NetBSD. */
-#define UPTR(x) ((intptr_t)(x))
-#define LENC(x) (x)
-#else
-#define UPTR(x) (x)
-#define LENC(x) ((int)(x))
-#endif
-#elif defined(HAVE_EPOLL)
-#include <sys/epoll.h>
-#elif defined(HAVE_POLL)
-#if defined(HAVE_PSELECT)
+#ifdef HAVE_PSELECT
#include <sys/select.h>
#endif
-#include <poll.h>
-#endif
-
-#ifdef WARN_SELECT
-#if defined(HAVE_KQUEUE)
-#pragma message("Compiling eloop with kqueue(2) support.")
-#elif defined(HAVE_EPOLL)
-#pragma message("Compiling eloop with epoll(7) support.")
-#elif defined(HAVE_PSELECT)
-#pragma message("Compiling eloop with pselect(2) support.")
-#elif defined(HAVE_PPOLL)
-#pragma message("Compiling eloop with ppoll(2) support.")
-#elif defined(HAVE_POLLTS)
-#pragma message("Compiling eloop with pollts(2) support.")
-#else
-#error Unknown select mechanism for eloop
-#endif
-#endif
/* Our structures require TAILQ macros, which really every libc should
* ship as they are useful beyond belief.
void *read_cb_arg;
void (*write_cb)(void *);
void *write_cb_arg;
+ struct pollfd *pollfd;
};
struct eloop_timeout {
};
struct eloop {
- size_t events_len;
TAILQ_HEAD (event_head, eloop_event) events;
+ size_t nevents;
struct event_head free_events;
- int events_maxfd;
- struct eloop_event **event_fds;
struct timespec now;
TAILQ_HEAD (timeout_head, eloop_timeout) timeouts;
void (*signal_cb)(int, void *);
void *signal_cb_ctx;
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
- int poll_fd;
-#elif defined(HAVE_POLL)
struct pollfd *fds;
- size_t fds_len;
-#endif
+ size_t nfds;
int exitnow;
int exitcode;
}
#endif
-#ifdef HAVE_POLL
-static void
-eloop_event_setup_fds(struct eloop *eloop)
-{
- struct eloop_event *e;
- size_t i;
-
- i = 0;
- TAILQ_FOREACH(e, &eloop->events, next) {
- eloop->fds[i].fd = e->fd;
- eloop->fds[i].events = 0;
- if (e->read_cb)
- eloop->fds[i].events |= POLLIN;
- if (e->write_cb)
- eloop->fds[i].events |= POLLOUT;
- eloop->fds[i].revents = 0;
- i++;
- }
-}
-
-#ifdef ELOOP_NEED_POLLTS
-/* Wrapper around pselect, to imitate the NetBSD pollts call. */
+#ifdef HAVE_PSELECT
+/* Wrapper around pselect, to imitate the ppoll call. */
static int
-eloop_pollts(struct pollfd * fds, nfds_t nfds,
+eloop_ppoll(struct pollfd * fds, nfds_t nfds,
const struct timespec *ts, const sigset_t *sigmask)
{
fd_set read_fds, write_fds;
return r;
}
-#endif /* pollts */
-#else /* !HAVE_POLL */
-#define eloop_event_setup_fds(a) {}
-#endif /* HAVE_POLL */
+#endif
unsigned long long
eloop_timespec_diff(const struct timespec *tsp, const struct timespec *usp,
eloop->now = now;
}
+static void
+eloop_event_setup_fds(struct eloop *eloop)
+{
+ struct eloop_event *e;
+ struct pollfd *pfd;
+
+ pfd = eloop->fds;
+ TAILQ_FOREACH(e, &eloop->events, next) {
+ e->pollfd = pfd;
+ pfd->fd = e->fd;
+ pfd->events = 0;
+ if (e->read_cb != NULL)
+ pfd->events |= POLLIN;
+ if (e->write_cb != NULL)
+ pfd->events |= POLLOUT;
+ pfd->revents = 0;
+ pfd++;
+ }
+}
+
int
eloop_event_add_rw(struct eloop *eloop, int fd,
void (*read_cb)(void *), void *read_cb_arg,
void (*write_cb)(void *), void *write_cb_arg)
{
struct eloop_event *e;
-#if defined(HAVE_KQUEUE)
- struct kevent ke[2];
-#elif defined(HAVE_EPOLL)
- struct epoll_event epe;
-#elif defined(HAVE_POLL)
- struct pollfd *nfds;
-#endif
+ struct pollfd *pfd;
assert(eloop != NULL);
assert(read_cb != NULL || write_cb != NULL);
return -1;
}
-#ifdef HAVE_EPOLL
- memset(&epe, 0, sizeof(epe));
- epe.data.fd = fd;
- epe.events = EPOLLIN;
- if (write_cb)
- epe.events |= EPOLLOUT;
-#endif
-
- /* We should only have one callback monitoring the fd. */
- if (fd <= eloop->events_maxfd) {
- if ((e = eloop->event_fds[fd]) != NULL) {
- int error;
-
-#if defined(HAVE_KQUEUE)
- EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ, EV_ADD,
- 0, 0, UPTR(e));
- if (write_cb)
- EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
- EV_ADD, 0, 0, UPTR(e));
- else if (e->write_cb)
- EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
- EV_DELETE, 0, 0, UPTR(e));
- error = kevent(eloop->poll_fd, ke,
- e->write_cb || write_cb ? 2 : 1, NULL, 0, NULL);
-#elif defined(HAVE_EPOLL)
- epe.data.ptr = e;
- error = epoll_ctl(eloop->poll_fd, EPOLL_CTL_MOD,
- fd, &epe);
-#else
- error = 0;
-#endif
- if (read_cb) {
- e->read_cb = read_cb;
- e->read_cb_arg = read_cb_arg;
- }
- if (write_cb) {
- e->write_cb = write_cb;
- e->write_cb_arg = write_cb_arg;
- }
- eloop_event_setup_fds(eloop);
- return error;
- }
- } else {
- struct eloop_event **new_fds;
- int maxfd, i;
-
- /* Reserve ourself and 4 more. */
- maxfd = fd + 4;
- new_fds = eloop_realloca(eloop->event_fds,
- ((size_t)maxfd + 1), sizeof(*eloop->event_fds));
- if (new_fds == NULL)
- return -1;
-
- /* set new entries NULL as the fd's may not be contiguous. */
- for (i = maxfd; i > eloop->events_maxfd; i--)
- new_fds[i] = NULL;
-
- eloop->event_fds = new_fds;
- eloop->events_maxfd = maxfd;
+ TAILQ_FOREACH(e, &eloop->events, next) {
+ if (e->fd == fd)
+ break;
}
- /* Allocate a new event if no free ones already allocated. */
- if ((e = TAILQ_FIRST(&eloop->free_events))) {
- TAILQ_REMOVE(&eloop->free_events, e, next);
- } else {
- e = malloc(sizeof(*e));
- if (e == NULL)
- goto err;
- }
+ if (e == NULL) {
+ if (eloop->nevents + 1 > eloop->nfds) {
+ pfd = eloop_realloca(eloop->fds, eloop->nevents + 1,
+ sizeof(*pfd));
+ if (pfd == NULL)
+ return -1;
+ eloop->fds = pfd;
+ eloop->nfds++;
+ }
- /* Ensure we can actually listen to it. */
- eloop->events_len++;
-#ifdef HAVE_POLL
- if (eloop->events_len > eloop->fds_len) {
- nfds = eloop_realloca(eloop->fds,
- (eloop->fds_len + 5), sizeof(*eloop->fds));
- if (nfds == NULL)
- goto err;
- eloop->fds_len += 5;
- eloop->fds = nfds;
+ e = TAILQ_FIRST(&eloop->free_events);
+ if (e != NULL)
+ TAILQ_REMOVE(&eloop->free_events, e, next);
+ else {
+ e = malloc(sizeof(*e));
+ if (e == NULL)
+ return -1;
+ TAILQ_INSERT_HEAD(&eloop->events, e, next);
+ }
+ e->fd = fd;
+ eloop->nevents++;
}
-#endif
- /* Now populate the structure and add it to the list. */
- e->fd = fd;
e->read_cb = read_cb;
e->read_cb_arg = read_cb_arg;
e->write_cb = write_cb;
e->write_cb_arg = write_cb_arg;
-#if defined(HAVE_KQUEUE)
- if (read_cb != NULL)
- EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ,
- EV_ADD, 0, 0, UPTR(e));
- if (write_cb != NULL)
- EV_SET(&ke[1], (uintptr_t)fd, EVFILT_WRITE,
- EV_ADD, 0, 0, UPTR(e));
- if (kevent(eloop->poll_fd, ke, write_cb ? 2 : 1, NULL, 0, NULL) == -1)
- goto err;
-#elif defined(HAVE_EPOLL)
- epe.data.ptr = e;
- if (epoll_ctl(eloop->poll_fd, EPOLL_CTL_ADD, fd, &epe) == -1)
- goto err;
-#endif
-
- TAILQ_INSERT_HEAD(&eloop->events, e, next);
- eloop->event_fds[e->fd] = e;
eloop_event_setup_fds(eloop);
return 0;
-
-err:
- if (e) {
- eloop->events_len--;
- TAILQ_INSERT_TAIL(&eloop->free_events, e, next);
- }
- return -1;
}
int
eloop_event_delete_write(struct eloop *eloop, int fd, int write_only)
{
struct eloop_event *e;
-#if defined(HAVE_KQUEUE)
- struct kevent ke[2];
-#elif defined(HAVE_EPOLL)
- struct epoll_event epe;
-#endif
assert(eloop != NULL);
- if (fd > eloop->events_maxfd ||
- (e = eloop->event_fds[fd]) == NULL)
- {
+ TAILQ_FOREACH(e, &eloop->events, next) {
+ if (e->fd == fd)
+ break;
+ }
+ if (e == NULL) {
errno = ENOENT;
return -1;
}
goto remove;
e->write_cb = NULL;
e->write_cb_arg = NULL;
-#if defined(HAVE_KQUEUE)
- EV_SET(&ke[0], (uintptr_t)e->fd,
- EVFILT_WRITE, EV_DELETE, 0, 0, UPTR(NULL));
- kevent(eloop->poll_fd, ke, 1, NULL, 0, NULL);
-#elif defined(HAVE_EPOLL)
- memset(&epe, 0, sizeof(epe));
- epe.data.fd = e->fd;
- epe.data.ptr = e;
- epe.events = EPOLLIN;
- epoll_ctl(eloop->poll_fd, EPOLL_CTL_MOD, fd, &epe);
-#endif
- eloop_event_setup_fds(eloop);
- return 1;
+ goto done;
}
remove:
TAILQ_REMOVE(&eloop->events, e, next);
- eloop->event_fds[e->fd] = NULL;
TAILQ_INSERT_TAIL(&eloop->free_events, e, next);
- eloop->events_len--;
-
-#if defined(HAVE_KQUEUE)
- EV_SET(&ke[0], (uintptr_t)fd, EVFILT_READ,
- EV_DELETE, 0, 0, UPTR(NULL));
- if (e->write_cb)
- EV_SET(&ke[1], (uintptr_t)fd,
- EVFILT_WRITE, EV_DELETE, 0, 0, UPTR(NULL));
- kevent(eloop->poll_fd, ke, e->write_cb ? 2 : 1, NULL, 0, NULL);
-#elif defined(HAVE_EPOLL)
- /* NULL event is safe because we
- * rely on epoll_pwait which as added
- * after the delete without event was fixed. */
- epoll_ctl(eloop->poll_fd, EPOLL_CTL_DEL, fd, NULL);
-#endif
+ eloop->nevents--;
+done:
eloop_event_setup_fds(eloop);
return 1;
}
(unsigned int)seconds, (unsigned int)nseconds, callback, arg);
}
-#if !defined(HAVE_KQUEUE)
static int
eloop_timeout_add_now(struct eloop *eloop,
void (*callback)(void *), void *arg)
eloop->timeout0_arg = arg;
return 0;
}
-#endif
int
eloop_q_timeout_delete(struct eloop *eloop, int queue,
eloop->exitnow = 0;
}
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
-static int
-eloop_open(struct eloop *eloop)
-{
-
-#if defined(HAVE_KQUEUE1)
- return (eloop->poll_fd = kqueue1(O_CLOEXEC));
-#elif defined(HAVE_KQUEUE)
- int i;
-
- if ((eloop->poll_fd = kqueue()) == -1)
- return -1;
- if ((i = fcntl(eloop->poll_fd, F_GETFD, 0)) == -1 ||
- fcntl(eloop->poll_fd, F_SETFD, i | FD_CLOEXEC) == -1)
- {
- close(eloop->poll_fd);
- eloop->poll_fd = -1;
- }
-
- return eloop->poll_fd;
-#elif defined (HAVE_EPOLL)
- return (eloop->poll_fd = epoll_create1(EPOLL_CLOEXEC));
-#else
- return (eloop->poll_fd = -1);
-#endif
-}
-#endif
-
-int
-eloop_requeue(struct eloop *eloop)
-{
-#if defined(HAVE_POLL)
-
- UNUSED(eloop);
- return 0;
-#else /* !HAVE_POLL */
- struct eloop_event *e;
- int error;
-#if defined(HAVE_KQUEUE)
- size_t i;
- struct kevent *ke;
-#elif defined(HAVE_EPOLL)
- struct epoll_event epe;
-#endif
-
- assert(eloop != NULL);
-
- if (eloop->poll_fd != -1)
- close(eloop->poll_fd);
- if (eloop_open(eloop) == -1)
- return -1;
-#if defined (HAVE_KQUEUE)
- i = eloop->signals_len;
- TAILQ_FOREACH(e, &eloop->events, next) {
- i++;
- if (e->write_cb)
- i++;
- }
-
- if ((ke = malloc(sizeof(*ke) * i)) == NULL)
- return -1;
-
- for (i = 0; i < eloop->signals_len; i++)
- EV_SET(&ke[i], (uintptr_t)eloop->signals[i],
- EVFILT_SIGNAL, EV_ADD, 0, 0, UPTR(NULL));
-
- TAILQ_FOREACH(e, &eloop->events, next) {
- EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_READ,
- EV_ADD, 0, 0, UPTR(e));
- i++;
- if (e->write_cb) {
- EV_SET(&ke[i], (uintptr_t)e->fd, EVFILT_WRITE,
- EV_ADD, 0, 0, UPTR(e));
- i++;
- }
- }
-
- error = kevent(eloop->poll_fd, ke, LENC(i), NULL, 0, NULL);
- free(ke);
-
-#elif defined(HAVE_EPOLL)
-
- error = 0;
- TAILQ_FOREACH(e, &eloop->events, next) {
- memset(&epe, 0, sizeof(epe));
- epe.data.fd = e->fd;
- epe.events = EPOLLIN;
- if (e->write_cb)
- epe.events |= EPOLLOUT;
- epe.data.ptr = e;
- if (epoll_ctl(eloop->poll_fd, EPOLL_CTL_ADD, e->fd, &epe) == -1)
- error = -1;
- }
-#endif
-
- return error;
-#endif /* HAVE_POLL */
-}
-
-int
+void
eloop_signal_set_cb(struct eloop *eloop,
const int *signals, size_t signals_len,
void (*signal_cb)(int, void *), void *signal_cb_ctx)
eloop->signals_len = signals_len;
eloop->signal_cb = signal_cb;
eloop->signal_cb_ctx = signal_cb_ctx;
- return eloop_requeue(eloop);
}
-#ifndef HAVE_KQUEUE
struct eloop_siginfo {
int sig;
struct eloop *eloop;
eloop_timeout_add_now(_eloop_siginfo.eloop,
eloop_signal1, &_eloop_siginfo);
}
-#endif
int
eloop_signal_mask(struct eloop *eloop, sigset_t *oldset)
{
sigset_t newset;
size_t i;
-#ifndef HAVE_KQUEUE
- struct sigaction sa;
-#endif
+ struct sigaction sa = {
+ .sa_sigaction = eloop_signal3,
+ .sa_flags = SA_SIGINFO,
+ };
assert(eloop != NULL);
if (sigprocmask(SIG_SETMASK, &newset, oldset) == -1)
return -1;
-#ifndef HAVE_KQUEUE
_eloop = eloop;
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_sigaction = eloop_signal3;
- sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
for (i = 0; i < eloop->signals_len; i++) {
if (sigaction(eloop->signals[i], &sa, NULL) == -1)
return -1;
}
-#endif
return 0;
}
}
TAILQ_INIT(&eloop->events);
- eloop->events_maxfd = -1;
TAILQ_INIT(&eloop->free_events);
TAILQ_INIT(&eloop->timeouts);
TAILQ_INIT(&eloop->free_timeouts);
eloop->exitcode = EXIT_FAILURE;
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
- if (eloop_open(eloop) == -1) {
- eloop_free(eloop);
- return NULL;
- }
-#endif
-
return eloop;
}
if (eloop == NULL)
return;
- free(eloop->event_fds);
- eloop->event_fds = NULL;
- eloop->events_len = 0;
- eloop->events_maxfd = -1;
+ eloop->nevents = 0;
eloop->signals = NULL;
eloop->signals_len = 0;
free(t);
}
-#if defined(HAVE_POLL)
free(eloop->fds);
eloop->fds = NULL;
- eloop->fds_len = 0;
-#endif
+ eloop->nfds = 0;
}
void
eloop_free(struct eloop *eloop)
{
-#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
- if (eloop != NULL)
- close(eloop->poll_fd);
-#endif
eloop_clear(eloop);
free(eloop);
}
struct eloop_event *e;
struct eloop_timeout *t;
void (*t0)(void *);
-#if defined(HAVE_KQUEUE)
- struct kevent ke;
- UNUSED(signals);
-#elif defined(HAVE_EPOLL)
- struct epoll_event epe;
-#endif
-#if defined(HAVE_KQUEUE) || defined(HAVE_POLL)
struct timespec ts, *tsp;
-#endif
-#ifndef HAVE_KQUEUE
- int timeout;
-#endif
assert(eloop != NULL);
}
t = TAILQ_FIRST(&eloop->timeouts);
- if (t == NULL && eloop->events_len == 0)
+ if (t == NULL && eloop->nevents == 0)
break;
if (t != NULL)
}
if (t != NULL) {
-#if defined(HAVE_KQUEUE) || defined(HAVE_POLL)
if (t->seconds > INT_MAX) {
ts.tv_sec = (time_t)INT_MAX;
ts.tv_nsec = 0;
ts.tv_nsec = (long)t->nseconds;
}
tsp = &ts;
-#endif
-
-#ifndef HAVE_KQUEUE
- if (t->seconds > INT_MAX / 1000 ||
- (t->seconds == INT_MAX / 1000 &&
- ((t->nseconds + 999999) / 1000000
- > INT_MAX % 1000000)))
- timeout = INT_MAX;
- else
- timeout = (int)(t->seconds * 1000 +
- (t->nseconds + 999999) / 1000000);
-#endif
- } else {
-#if defined(HAVE_KQUEUE) || defined(HAVE_POLL)
+ } else
tsp = NULL;
-#endif
-#ifndef HAVE_KQUEUE
- timeout = -1;
-#endif
- }
-#if defined(HAVE_KQUEUE)
- n = kevent(eloop->poll_fd, NULL, 0, &ke, 1, tsp);
-#elif defined(HAVE_EPOLL)
- if (signals)
- n = epoll_pwait(eloop->poll_fd, &epe, 1,
- timeout, signals);
- else
- n = epoll_wait(eloop->poll_fd, &epe, 1, timeout);
-#elif defined(HAVE_POLL)
- if (signals)
- n = POLLTS(eloop->fds, (nfds_t)eloop->events_len,
- tsp, signals);
- else
- n = poll(eloop->fds, (nfds_t)eloop->events_len,
- timeout);
-#endif
+ n = ppoll(eloop->fds, (nfds_t)eloop->nevents, tsp, signals);
if (n == -1) {
if (errno == EINTR)
continue;
if (n == 0)
continue;
- /* Process any triggered events.
- * We go back to the start after calling each callback incase
- * the current event or next event is removed. */
-#if defined(HAVE_KQUEUE)
- if (ke.filter == EVFILT_SIGNAL) {
- eloop->signal_cb((int)ke.ident,
- eloop->signal_cb_ctx);
- } else {
- e = (struct eloop_event *)ke.udata;
- if (ke.filter == EVFILT_WRITE && e->write_cb != NULL)
- e->write_cb(e->write_cb_arg);
- else if (ke.filter == EVFILT_READ && e->read_cb != NULL)
- e->read_cb(e->read_cb_arg);
- }
-#elif defined(HAVE_EPOLL)
- e = (struct eloop_event *)epe.data.ptr;
- if (epe.events & EPOLLOUT && e->write_cb != NULL)
- e->write_cb(e->write_cb_arg);
- else if (epe.events & (EPOLLIN | EPOLLERR | EPOLLHUP) &&
- e->read_cb != NULL)
- e->read_cb(e->read_cb_arg);
-#elif defined(HAVE_POLL)
- size_t i;
-
- for (i = 0; i < eloop->events_len; i++) {
- if (eloop->fds[i].revents & POLLOUT) {
- e = eloop->event_fds[eloop->fds[i].fd];
+ TAILQ_FOREACH(e, &eloop->events, next) {
+ if (e->pollfd->revents & POLLOUT) {
if (e->write_cb != NULL) {
e->write_cb(e->write_cb_arg);
break;
}
}
- if (eloop->fds[i].revents) {
- e = eloop->event_fds[eloop->fds[i].fd];
+ if (e->pollfd->revents) {
if (e->read_cb != NULL) {
e->read_cb(e->read_cb_arg);
break;
}
}
}
-#endif
}
return eloop->exitcode;