mirror of https://github.com/getdnsapi/getdns.git
Choice of poll or select based default event loop
This commit is contained in:
parent
dad4aaf6d8
commit
60443fb7fd
27
configure.ac
27
configure.ac
|
@ -214,6 +214,31 @@ case "$enable_debug_keep_connections_open" in
|
|||
;;
|
||||
esac
|
||||
|
||||
|
||||
DEFAULT_EVENTLOOP=select_eventloop
|
||||
AC_CHECK_HEADERS([sys/poll.h poll.h sys/resource.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_FUNCS([getrlimit])
|
||||
AC_ARG_ENABLE(poll-eventloop, AC_HELP_STRING([--disable-poll-eventloop], [Disable default eventloop based on poll (default=enabled if available)]))
|
||||
case "$enable_poll_eventloop" in
|
||||
no)
|
||||
;;
|
||||
yes|*)
|
||||
AC_MSG_CHECKING(for poll)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([
|
||||
#ifdef HAVE_SYS_POLL_H
|
||||
#include <sys/poll.h>
|
||||
#else
|
||||
#include <poll.h>
|
||||
#endif
|
||||
], [int rc; rc = poll((struct pollfd *)(0), 0, 0);])], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE_UNQUOTED([USE_POLL_DEFAULT_EVENTLOOP], [1], [Define this to enable a default eventloop based on poll().])
|
||||
DEFAULT_EVENTLOOP=poll_eventloop
|
||||
],[AC_MSG_RESULT(no)])
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(DEFAULT_EVENTLOOP)
|
||||
|
||||
AC_ARG_ENABLE(tcp-fastopen, AC_HELP_STRING([--disable-tcp-fastopen], Disable TCP Fast Open (default=enabled if available)),
|
||||
enable_tcp_fastopen="$enableval", enable_tcp_fastopen=yes)
|
||||
if test "x$enable_tcp_fastopen" = xno; then
|
||||
|
@ -1076,8 +1101,6 @@ if test "$ac_cv_func_arc4random" = "no"; then
|
|||
])
|
||||
fi
|
||||
|
||||
AC_DEFINE(USE_MINI_EVENT, 1, [Needed for sync stub resolver functions])
|
||||
|
||||
AC_TYPE_SIGNAL
|
||||
|
||||
case `uname` in
|
||||
|
|
|
@ -65,6 +65,8 @@ EXTENSION_LIBUV_LDFLAGS=@EXTENSION_LIBUV_LDFLAGS@
|
|||
|
||||
C99COMPATFLAGS=@C99COMPATFLAGS@
|
||||
|
||||
DEFAULT_EVENTLOOP_OBJ=@DEFAULT_EVENTLOOP@.lo
|
||||
|
||||
GETDNS_OBJ=const-info.lo convert.lo dict.lo dnssec.lo general.lo \
|
||||
list.lo request-internal.lo pubkey-pinning.lo rr-dict.lo \
|
||||
rr-iter.lo server.lo stub.lo sync.lo ub_loop.lo util-internal.lo \
|
||||
|
@ -81,7 +83,7 @@ UTIL_OBJ=rbtree.lo val_secalgo.lo
|
|||
|
||||
JSMN_OBJ=jsmn.lo
|
||||
|
||||
EXTENSION_OBJ=default_eventloop.lo libevent.lo libev.lo
|
||||
EXTENSION_OBJ=$(DEFAULT_EVENTLOOP_OBJ) libevent.lo libev.lo
|
||||
|
||||
NON_C99_OBJS=context.lo libuv.lo
|
||||
|
||||
|
@ -152,8 +154,8 @@ libgetdns_ext_ev.la: libgetdns.la libev.lo
|
|||
$(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ libev.lo libgetdns.la $(LDFLAGS) $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/extension/libev.symbols
|
||||
|
||||
|
||||
libgetdns.la: $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ)
|
||||
$(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols
|
||||
libgetdns.la: $(GETDNS_OBJ) version.lo context.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ)
|
||||
$(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ $(GETDNS_OBJ) version.lo context.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols
|
||||
|
||||
test: all
|
||||
cd test && $(MAKE) $@
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* \file default_eventloop.h
|
||||
* @brief Build in default eventloop extension that uses select.
|
||||
* @brief Build in default eventloop extension that uses either poll or select.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
|
@ -32,29 +32,13 @@
|
|||
#ifndef DEFAULT_EVENTLOOP_H_
|
||||
#define DEFAULT_EVENTLOOP_H_
|
||||
#include "config.h"
|
||||
#include "getdns/getdns.h"
|
||||
#include "getdns/getdns_extra.h"
|
||||
#include "util/uthash.h"
|
||||
|
||||
/* Eventloop based on poll */
|
||||
|
||||
typedef struct _getdns_eventloop_info {
|
||||
int id;
|
||||
getdns_eventloop_event *event;
|
||||
uint64_t timeout_time;
|
||||
UT_hash_handle hh;
|
||||
} _getdns_eventloop_info;
|
||||
|
||||
typedef struct _getdns_default_eventloop {
|
||||
getdns_eventloop loop;
|
||||
unsigned int max_fds;
|
||||
unsigned int max_timeouts;
|
||||
_getdns_eventloop_info *fd_events;
|
||||
_getdns_eventloop_info *timeout_events;
|
||||
} _getdns_default_eventloop;
|
||||
|
||||
void
|
||||
_getdns_default_eventloop_init(_getdns_default_eventloop *loop);
|
||||
|
||||
#ifdef USE_POLL_DEFAULT_EVENTLOOP
|
||||
#include "extension/poll_eventloop.h"
|
||||
#define _getdns_default_eventloop _getdns_poll_eventloop
|
||||
#define _getdns_default_eventloop_init _getdns_poll_eventloop_init
|
||||
#else
|
||||
#include "extension/select_eventloop.h"
|
||||
#define _getdns_default_eventloop _getdns_select_eventloop
|
||||
#define _getdns_default_eventloop_init _getdns_select_eventloop_init
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -27,15 +27,20 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef USE_WINSOCK
|
||||
#ifdef HAVE_SYS_POLL_H
|
||||
#include <sys/poll.h>
|
||||
#else
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#include "extension/default_eventloop.h"
|
||||
#endif
|
||||
#include "extension/poll_eventloop.h"
|
||||
#include "debug.h"
|
||||
#include "types-internal.h"
|
||||
|
||||
_getdns_eventloop_info *find_event(_getdns_eventloop_info** events, int id)
|
||||
static _getdns_eventloop_info *
|
||||
find_event(_getdns_eventloop_info** events, int id)
|
||||
{
|
||||
_getdns_eventloop_info* ev;
|
||||
|
||||
|
@ -44,9 +49,10 @@ _getdns_eventloop_info *find_event(_getdns_eventloop_info** events, int id)
|
|||
return ev;
|
||||
}
|
||||
|
||||
void add_event(_getdns_eventloop_info** events, int id, _getdns_eventloop_info* ev)
|
||||
static void
|
||||
add_event(_getdns_eventloop_info** events, int id, _getdns_eventloop_info* ev)
|
||||
{
|
||||
DEBUG_SCHED("default_eventloop: add_event with id %d\n", id);
|
||||
DEBUG_SCHED("poll_eventloop: add_event with id %d\n", id);
|
||||
_getdns_eventloop_info* myevent = calloc(1, sizeof(_getdns_eventloop_info));
|
||||
myevent->event = ev->event;
|
||||
myevent->id = id;
|
||||
|
@ -54,9 +60,10 @@ void add_event(_getdns_eventloop_info** events, int id, _getdns_eventloop_info*
|
|||
HASH_ADD_INT(*events, id, myevent);
|
||||
}
|
||||
|
||||
void delete_event(_getdns_eventloop_info** events, _getdns_eventloop_info* ev)
|
||||
static void
|
||||
delete_event(_getdns_eventloop_info** events, _getdns_eventloop_info* ev)
|
||||
{
|
||||
DEBUG_SCHED("default_eventloop: delete_event with id %d\n", ev->id);
|
||||
DEBUG_SCHED("poll_eventloop: delete_event with id %d\n", ev->id);
|
||||
HASH_DEL(*events, ev);
|
||||
free(ev);
|
||||
}
|
||||
|
@ -77,30 +84,33 @@ static uint64_t get_now_plus(uint64_t amount)
|
|||
}
|
||||
|
||||
static getdns_return_t
|
||||
default_eventloop_schedule(getdns_eventloop *loop,
|
||||
poll_eventloop_schedule(getdns_eventloop *loop,
|
||||
int fd, uint64_t timeout, getdns_eventloop_event *event)
|
||||
{
|
||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
||||
_getdns_poll_eventloop *poll_loop = (_getdns_poll_eventloop *)loop;
|
||||
size_t i;
|
||||
|
||||
DEBUG_SCHED( "%s(loop: %p, fd: %d, timeout: %"PRIu64", event: %p, max_fds: %d)\n"
|
||||
, __FUNC__, (void *)loop, fd, timeout, (void *)event, default_loop->max_fds);
|
||||
, __FUNC__, (void *)loop, fd, timeout, (void *)event, poll_loop->max_fds);
|
||||
|
||||
if (!loop || !event)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
if (fd >= (int)default_loop->max_fds) {
|
||||
|
||||
#ifdef HAVE_GETRLIMIT
|
||||
if (fd >= (int)poll_loop->max_fds) {
|
||||
DEBUG_SCHED( "ERROR: fd %d >= max_fds: %d!\n"
|
||||
, fd, default_loop->max_fds);
|
||||
, fd, poll_loop->max_fds);
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
#endif
|
||||
if (fd >= 0 && !(event->read_cb || event->write_cb)) {
|
||||
DEBUG_SCHED("WARNING: fd event without "
|
||||
"read or write cb!\n");
|
||||
fd = -1;
|
||||
}
|
||||
if (fd >= 0) {
|
||||
_getdns_eventloop_info* fd_event = find_event(&default_loop->fd_events, fd);
|
||||
_getdns_eventloop_info* fd_event = find_event(&poll_loop->fd_events, fd);
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
if (fd_event) {
|
||||
if (fd_event->event == event) {
|
||||
|
@ -116,13 +126,13 @@ default_eventloop_schedule(getdns_eventloop *loop,
|
|||
#endif
|
||||
/* cleanup the old event if it exists */
|
||||
if (fd_event) {
|
||||
delete_event(&default_loop->fd_events, fd_event);
|
||||
delete_event(&poll_loop->fd_events, fd_event);
|
||||
}
|
||||
_getdns_eventloop_info fd_ev;
|
||||
event->ev = (void *) (intptr_t) (fd + 1);
|
||||
fd_ev.event = event;
|
||||
fd_ev.timeout_time = get_now_plus(timeout);
|
||||
add_event(&default_loop->fd_events, fd, &fd_ev);
|
||||
add_event(&poll_loop->fd_events, fd, &fd_ev);
|
||||
|
||||
DEBUG_SCHED( "scheduled read/write at fd %d\n", fd);
|
||||
return GETDNS_RETURN_GOOD;
|
||||
|
@ -139,12 +149,12 @@ default_eventloop_schedule(getdns_eventloop *loop,
|
|||
DEBUG_SCHED("ERROR: timeout event with write_cb! Clearing.\n");
|
||||
event->write_cb = NULL;
|
||||
}
|
||||
for (i = 0; i < default_loop->max_timeouts; i++) {
|
||||
if (find_event(&default_loop->timeout_events, i) == NULL) {
|
||||
for (i = poll_loop->timeout_id + 1; i != poll_loop->timeout_id; i++) {
|
||||
if (find_event(&poll_loop->timeout_events, i) == NULL) {
|
||||
_getdns_eventloop_info timeout_ev;
|
||||
timeout_ev.event = event;
|
||||
timeout_ev.timeout_time = get_now_plus(timeout);
|
||||
add_event(&default_loop->timeout_events, i, &timeout_ev);
|
||||
add_event(&poll_loop->timeout_events, i, &timeout_ev);
|
||||
event->ev = (void *) (intptr_t) (i + 1);
|
||||
|
||||
DEBUG_SCHED( "scheduled timeout at slot %d\n", (int)i);
|
||||
|
@ -156,9 +166,9 @@ default_eventloop_schedule(getdns_eventloop *loop,
|
|||
}
|
||||
|
||||
static getdns_return_t
|
||||
default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
||||
poll_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
||||
{
|
||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
||||
_getdns_poll_eventloop *poll_loop = (_getdns_poll_eventloop *)loop;
|
||||
ssize_t i;
|
||||
|
||||
if (!loop || !event)
|
||||
|
@ -167,11 +177,15 @@ default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
|||
DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNC__, (void *)loop, (void *)event);
|
||||
|
||||
i = (intptr_t)event->ev - 1;
|
||||
if (i < 0 || i > default_loop->max_fds) {
|
||||
if (i < 0
|
||||
#ifdef HAVE_GETRLIMIT
|
||||
|| i > poll_loop->max_fds
|
||||
#endif
|
||||
) {
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
if (event->timeout_cb && !event->read_cb && !event->write_cb) {
|
||||
_getdns_eventloop_info* timeout_event = find_event(&default_loop->timeout_events, i);
|
||||
_getdns_eventloop_info* timeout_event = find_event(&poll_loop->timeout_events, i);
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
if (timeout_event && timeout_event->event != event)
|
||||
DEBUG_SCHED( "ERROR: Different/wrong event present at "
|
||||
|
@ -180,10 +194,10 @@ default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
|||
|
||||
#endif
|
||||
if (timeout_event) {
|
||||
delete_event(&default_loop->timeout_events, timeout_event);
|
||||
delete_event(&poll_loop->timeout_events, timeout_event);
|
||||
}
|
||||
} else {
|
||||
_getdns_eventloop_info* fd_event = find_event(&default_loop->fd_events, i);
|
||||
_getdns_eventloop_info* fd_event = find_event(&poll_loop->fd_events, i);
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
if (fd_event && fd_event->event != event)
|
||||
DEBUG_SCHED( "ERROR: Different/wrong event present at "
|
||||
|
@ -191,7 +205,7 @@ default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
|||
, (void *)fd_event);
|
||||
#endif
|
||||
if (fd_event) {
|
||||
delete_event(&default_loop->fd_events, fd_event);
|
||||
delete_event(&poll_loop->fd_events, fd_event);
|
||||
}
|
||||
}
|
||||
event->ev = NULL;
|
||||
|
@ -199,15 +213,15 @@ default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
|||
}
|
||||
|
||||
static void
|
||||
default_eventloop_cleanup(getdns_eventloop *loop)
|
||||
poll_eventloop_cleanup(getdns_eventloop *loop)
|
||||
{
|
||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
||||
HASH_CLEAR(hh, default_loop->fd_events);
|
||||
HASH_CLEAR(hh, default_loop->timeout_events);
|
||||
_getdns_poll_eventloop *poll_loop = (_getdns_poll_eventloop *)loop;
|
||||
HASH_CLEAR(hh, poll_loop->fd_events);
|
||||
HASH_CLEAR(hh, poll_loop->timeout_events);
|
||||
}
|
||||
|
||||
static void
|
||||
default_read_cb(int fd, getdns_eventloop_event *event)
|
||||
poll_read_cb(int fd, getdns_eventloop_event *event)
|
||||
{
|
||||
#if !defined(SCHED_DEBUG) || !SCHED_DEBUG
|
||||
(void)fd;
|
||||
|
@ -217,7 +231,7 @@ default_read_cb(int fd, getdns_eventloop_event *event)
|
|||
}
|
||||
|
||||
static void
|
||||
default_write_cb(int fd, getdns_eventloop_event *event)
|
||||
poll_write_cb(int fd, getdns_eventloop_event *event)
|
||||
{
|
||||
#if !defined(SCHED_DEBUG) || !SCHED_DEBUG
|
||||
(void)fd;
|
||||
|
@ -227,7 +241,7 @@ default_write_cb(int fd, getdns_eventloop_event *event)
|
|||
}
|
||||
|
||||
static void
|
||||
default_timeout_cb(int fd, getdns_eventloop_event *event)
|
||||
poll_timeout_cb(int fd, getdns_eventloop_event *event)
|
||||
{
|
||||
#if !defined(SCHED_DEBUG) || !SCHED_DEBUG
|
||||
(void)fd;
|
||||
|
@ -237,9 +251,9 @@ default_timeout_cb(int fd, getdns_eventloop_event *event)
|
|||
}
|
||||
|
||||
static void
|
||||
default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
||||
poll_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
||||
{
|
||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
||||
_getdns_poll_eventloop *poll_loop = (_getdns_poll_eventloop *)loop;
|
||||
_getdns_eventloop_info *s, *tmp;
|
||||
uint64_t now, timeout = TIMEOUT_FOREVER;
|
||||
size_t i=0;
|
||||
|
@ -254,7 +268,7 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
|||
|
||||
now = get_now_plus(0);
|
||||
|
||||
HASH_ITER(hh, default_loop->timeout_events, s, tmp) {
|
||||
HASH_ITER(hh, poll_loop->timeout_events, s, tmp) {
|
||||
if (now > s->timeout_time)
|
||||
add_event(&timeout_timeout_cbs, s->id, s);
|
||||
else if (s->timeout_time < timeout)
|
||||
|
@ -265,10 +279,10 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
|||
HASH_ITER(hh, timeout_timeout_cbs, s, tmp) {
|
||||
getdns_eventloop_event* event = s->event;
|
||||
delete_event(&timeout_timeout_cbs, s);
|
||||
default_timeout_cb(-1, event);
|
||||
poll_timeout_cb(-1, event);
|
||||
}
|
||||
// first we count the number of fds that will be active
|
||||
HASH_ITER(hh, default_loop->fd_events, s, tmp) {
|
||||
HASH_ITER(hh, poll_loop->fd_events, s, tmp) {
|
||||
if (s->event->read_cb ||
|
||||
s->event->write_cb)
|
||||
num_pfds++;
|
||||
|
@ -281,7 +295,7 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
|||
|
||||
pfds = calloc(num_pfds, sizeof(struct pollfd));
|
||||
i = 0;
|
||||
HASH_ITER(hh, default_loop->fd_events, s, tmp) {
|
||||
HASH_ITER(hh, poll_loop->fd_events, s, tmp) {
|
||||
if (s->event->read_cb) {
|
||||
pfds[i].fd = s->id;
|
||||
pfds[i].events |= POLLIN;
|
||||
|
@ -312,21 +326,21 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
|||
now = get_now_plus(0);
|
||||
for (i = 0; i < num_pfds; i++) {
|
||||
int fd = pfds[i].fd;
|
||||
_getdns_eventloop_info* fd_event = find_event(&default_loop->fd_events, fd);
|
||||
_getdns_eventloop_info* fd_event = find_event(&poll_loop->fd_events, fd);
|
||||
if (fd_event && fd_event->event) {
|
||||
getdns_eventloop_event* event = fd_event->event;
|
||||
if (event->read_cb &&
|
||||
(pfds[i].revents & POLLIN))
|
||||
default_read_cb(fd, event);
|
||||
poll_read_cb(fd, event);
|
||||
|
||||
if (event->write_cb &&
|
||||
(pfds[i].revents & POLLOUT))
|
||||
default_write_cb(fd, event);
|
||||
poll_write_cb(fd, event);
|
||||
}
|
||||
}
|
||||
if (pfds)
|
||||
free(pfds);
|
||||
HASH_ITER(hh, default_loop->fd_events, s, tmp) {
|
||||
HASH_ITER(hh, poll_loop->fd_events, s, tmp) {
|
||||
if (s->event &&
|
||||
s->event->timeout_cb &&
|
||||
now > s->timeout_time)
|
||||
|
@ -338,9 +352,9 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
|||
int fd = s->id;
|
||||
getdns_eventloop_event* event = s->event;
|
||||
delete_event(&fd_timeout_cbs, s);
|
||||
default_timeout_cb(fd, event);
|
||||
poll_timeout_cb(fd, event);
|
||||
}
|
||||
HASH_ITER(hh, default_loop->timeout_events, s, tmp) {
|
||||
HASH_ITER(hh, poll_loop->timeout_events, s, tmp) {
|
||||
if (s->event &&
|
||||
s->event->timeout_cb &&
|
||||
now > s->timeout_time)
|
||||
|
@ -351,46 +365,51 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
|||
HASH_ITER(hh, timeout_timeout_cbs, s, tmp) {
|
||||
getdns_eventloop_event* event = s->event;
|
||||
delete_event(&timeout_timeout_cbs, s);
|
||||
default_timeout_cb(-1, event);
|
||||
poll_timeout_cb(-1, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
default_eventloop_run(getdns_eventloop *loop)
|
||||
poll_eventloop_run(getdns_eventloop *loop)
|
||||
{
|
||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
||||
_getdns_poll_eventloop *poll_loop = (_getdns_poll_eventloop *)loop;
|
||||
|
||||
if (!loop)
|
||||
return;
|
||||
|
||||
/* keep going until all the events are cleared */
|
||||
while (default_loop->fd_events || default_loop->timeout_events) {
|
||||
default_eventloop_run_once(loop, 1);
|
||||
while (poll_loop->fd_events || poll_loop->timeout_events) {
|
||||
poll_eventloop_run_once(loop, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_getdns_default_eventloop_init(_getdns_default_eventloop *loop)
|
||||
_getdns_poll_eventloop_init(_getdns_poll_eventloop *loop)
|
||||
{
|
||||
static getdns_eventloop_vmt default_eventloop_vmt = {
|
||||
default_eventloop_cleanup,
|
||||
default_eventloop_schedule,
|
||||
default_eventloop_clear,
|
||||
default_eventloop_run,
|
||||
default_eventloop_run_once
|
||||
#ifdef HAVE_GETRLIMIT
|
||||
struct rlimit rl;
|
||||
#endif
|
||||
static getdns_eventloop_vmt poll_eventloop_vmt = {
|
||||
poll_eventloop_cleanup,
|
||||
poll_eventloop_schedule,
|
||||
poll_eventloop_clear,
|
||||
poll_eventloop_run,
|
||||
poll_eventloop_run_once
|
||||
};
|
||||
|
||||
(void) memset(loop, 0, sizeof(_getdns_default_eventloop));
|
||||
loop->loop.vmt = &default_eventloop_vmt;
|
||||
(void) memset(loop, 0, sizeof(_getdns_poll_eventloop));
|
||||
loop->loop.vmt = &poll_eventloop_vmt;
|
||||
|
||||
struct rlimit rl;
|
||||
#ifdef HAVE_GETRLIMIT
|
||||
if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
|
||||
loop->max_fds = rl.rlim_cur;
|
||||
loop->max_timeouts = loop->max_fds; /* this is somewhat arbitrary */
|
||||
} else {
|
||||
DEBUG_SCHED("ERROR: could not obtain RLIMIT_NOFILE from getrlimit()\n");
|
||||
#endif
|
||||
loop->max_fds = 0;
|
||||
loop->max_timeouts = loop->max_fds;
|
||||
#if HAVE_GETRLIMIT
|
||||
}
|
||||
#endif
|
||||
loop->timeout_id = 0;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* \file poll_eventloop.h
|
||||
* @brief Build in default eventloop extension that uses select.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2013, NLNet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef POLL_EVENTLOOP_H_
|
||||
#define POLL_EVENTLOOP_H_
|
||||
#include "config.h"
|
||||
#include "getdns/getdns.h"
|
||||
#include "getdns/getdns_extra.h"
|
||||
#include "util/uthash.h"
|
||||
|
||||
/* Eventloop based on poll */
|
||||
|
||||
typedef struct _getdns_eventloop_info {
|
||||
int id;
|
||||
getdns_eventloop_event *event;
|
||||
uint64_t timeout_time;
|
||||
UT_hash_handle hh;
|
||||
} _getdns_eventloop_info;
|
||||
|
||||
typedef struct _getdns_poll_eventloop {
|
||||
getdns_eventloop loop;
|
||||
unsigned int max_fds;
|
||||
unsigned int timeout_id;
|
||||
_getdns_eventloop_info *fd_events;
|
||||
_getdns_eventloop_info *timeout_events;
|
||||
} _getdns_poll_eventloop;
|
||||
|
||||
void
|
||||
_getdns_poll_eventloop_init(_getdns_poll_eventloop *loop);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* Copyright (c) 2013, NLNet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "extension/select_eventloop.h"
|
||||
#include "debug.h"
|
||||
#include "types-internal.h"
|
||||
|
||||
static uint64_t get_now_plus(uint64_t amount)
|
||||
{
|
||||
struct timeval tv;
|
||||
uint64_t now;
|
||||
|
||||
if (gettimeofday(&tv, NULL)) {
|
||||
perror("gettimeofday() failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
now = tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
|
||||
return (now + amount * 1000) >= now
|
||||
? now + amount * 1000 : TIMEOUT_FOREVER;
|
||||
}
|
||||
|
||||
static getdns_return_t
|
||||
select_eventloop_schedule(getdns_eventloop *loop,
|
||||
int fd, uint64_t timeout, getdns_eventloop_event *event)
|
||||
{
|
||||
_getdns_select_eventloop *select_loop = (_getdns_select_eventloop *)loop;
|
||||
size_t i;
|
||||
|
||||
DEBUG_SCHED( "%s(loop: %p, fd: %d, timeout: %"PRIu64", event: %p, FD_SETSIZE: %d)\n"
|
||||
, __FUNC__, (void *)loop, fd, timeout, (void *)event, FD_SETSIZE);
|
||||
|
||||
if (!loop || !event)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
if (fd >= (int)FD_SETSIZE) {
|
||||
DEBUG_SCHED( "ERROR: fd %d >= FD_SETSIZE: %d!\n"
|
||||
, fd, FD_SETSIZE);
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
if (fd >= 0 && !(event->read_cb || event->write_cb)) {
|
||||
DEBUG_SCHED("WARNING: fd event without "
|
||||
"read or write cb!\n");
|
||||
fd = -1;
|
||||
}
|
||||
if (fd >= 0) {
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
if (select_loop->fd_events[fd]) {
|
||||
if (select_loop->fd_events[fd] == event) {
|
||||
DEBUG_SCHED("WARNING: Event %p not cleared "
|
||||
"before being rescheduled!\n"
|
||||
, (void *)select_loop->fd_events[fd]);
|
||||
} else {
|
||||
DEBUG_SCHED("ERROR: A different event is "
|
||||
"already present at fd slot: %p!\n"
|
||||
, (void *)select_loop->fd_events[fd]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
select_loop->fd_events[fd] = event;
|
||||
select_loop->fd_timeout_times[fd] = get_now_plus(timeout);
|
||||
event->ev = (void *)(intptr_t)(fd + 1);
|
||||
DEBUG_SCHED( "scheduled read/write at %d\n", fd);
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
if (!event->timeout_cb) {
|
||||
DEBUG_SCHED("ERROR: fd < 0 without timeout_cb!\n");
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
if (event->read_cb) {
|
||||
DEBUG_SCHED("ERROR: timeout event with read_cb! Clearing.\n");
|
||||
event->read_cb = NULL;
|
||||
}
|
||||
if (event->write_cb) {
|
||||
DEBUG_SCHED("ERROR: timeout event with write_cb! Clearing.\n");
|
||||
event->write_cb = NULL;
|
||||
}
|
||||
for (i = 0; i < MAX_TIMEOUTS; i++) {
|
||||
if (select_loop->timeout_events[i] == NULL) {
|
||||
select_loop->timeout_events[i] = event;
|
||||
select_loop->timeout_times[i] = get_now_plus(timeout);
|
||||
event->ev = (void *)(intptr_t)(i + 1);
|
||||
DEBUG_SCHED( "scheduled timeout at %d\n", (int)i);
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
}
|
||||
DEBUG_SCHED("ERROR: Out of timeout slots!\n");
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
static getdns_return_t
|
||||
select_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
||||
{
|
||||
_getdns_select_eventloop *select_loop = (_getdns_select_eventloop *)loop;
|
||||
ssize_t i;
|
||||
|
||||
if (!loop || !event)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNC__, (void *)loop, (void *)event);
|
||||
|
||||
i = (intptr_t)event->ev - 1;
|
||||
if (i < 0 || i >= FD_SETSIZE) {
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
if (event->timeout_cb && !event->read_cb && !event->write_cb) {
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
if (select_loop->timeout_events[i] != event)
|
||||
DEBUG_SCHED( "ERROR: Different/wrong event present at "
|
||||
"timeout slot: %p!\n"
|
||||
, (void *)select_loop->timeout_events[i]);
|
||||
#endif
|
||||
select_loop->timeout_events[i] = NULL;
|
||||
} else {
|
||||
#if defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||
if (select_loop->fd_events[i] != event)
|
||||
DEBUG_SCHED( "ERROR: Different/wrong event present at "
|
||||
"fd slot: %p!\n"
|
||||
, (void *)select_loop->fd_events[i]);
|
||||
#endif
|
||||
select_loop->fd_events[i] = NULL;
|
||||
}
|
||||
event->ev = NULL;
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
static void
|
||||
select_eventloop_cleanup(getdns_eventloop *loop)
|
||||
{
|
||||
(void)loop;
|
||||
}
|
||||
|
||||
static void
|
||||
select_read_cb(int fd, getdns_eventloop_event *event)
|
||||
{
|
||||
#if !defined(SCHED_DEBUG) || !SCHED_DEBUG
|
||||
(void)fd;
|
||||
#endif
|
||||
DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNC__, fd, (void *)event);
|
||||
event->read_cb(event->userarg);
|
||||
}
|
||||
|
||||
static void
|
||||
select_write_cb(int fd, getdns_eventloop_event *event)
|
||||
{
|
||||
#if !defined(SCHED_DEBUG) || !SCHED_DEBUG
|
||||
(void)fd;
|
||||
#endif
|
||||
DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNC__, fd, (void *)event);
|
||||
event->write_cb(event->userarg);
|
||||
}
|
||||
|
||||
static void
|
||||
select_timeout_cb(int fd, getdns_eventloop_event *event)
|
||||
{
|
||||
#if !defined(SCHED_DEBUG) || !SCHED_DEBUG
|
||||
(void)fd;
|
||||
#endif
|
||||
DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNC__, fd, (void *)event);
|
||||
event->timeout_cb(event->userarg);
|
||||
}
|
||||
|
||||
static void
|
||||
select_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
||||
{
|
||||
_getdns_select_eventloop *select_loop = (_getdns_select_eventloop *)loop;
|
||||
|
||||
fd_set readfds, writefds;
|
||||
int fd, max_fd = -1;
|
||||
uint64_t now, timeout = TIMEOUT_FOREVER;
|
||||
size_t i;
|
||||
struct timeval tv;
|
||||
|
||||
if (!loop)
|
||||
return;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
now = get_now_plus(0);
|
||||
|
||||
for (i = 0; i < MAX_TIMEOUTS; i++) {
|
||||
if (!select_loop->timeout_events[i])
|
||||
continue;
|
||||
if (now > select_loop->timeout_times[i])
|
||||
select_timeout_cb(-1, select_loop->timeout_events[i]);
|
||||
else if (select_loop->timeout_times[i] < timeout)
|
||||
timeout = select_loop->timeout_times[i];
|
||||
}
|
||||
for (fd = 0; fd < (int)FD_SETSIZE; fd++) {
|
||||
if (!select_loop->fd_events[fd])
|
||||
continue;
|
||||
if (select_loop->fd_events[fd]->read_cb)
|
||||
FD_SET(fd, &readfds);
|
||||
if (select_loop->fd_events[fd]->write_cb)
|
||||
FD_SET(fd, &writefds);
|
||||
if (fd > max_fd)
|
||||
max_fd = fd;
|
||||
if (select_loop->fd_timeout_times[fd] < timeout)
|
||||
timeout = select_loop->fd_timeout_times[fd];
|
||||
}
|
||||
if (max_fd == -1 && timeout == TIMEOUT_FOREVER)
|
||||
return;
|
||||
|
||||
if (! blocking || now > timeout) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
} else {
|
||||
tv.tv_sec = (long)((timeout - now) / 1000000);
|
||||
tv.tv_usec = (long)((timeout - now) % 1000000);
|
||||
}
|
||||
if (select(max_fd + 1, &readfds, &writefds, NULL,
|
||||
(timeout == TIMEOUT_FOREVER ? NULL : &tv)) < 0) {
|
||||
perror("select() failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
now = get_now_plus(0);
|
||||
for (fd = 0; fd < (int)FD_SETSIZE; fd++) {
|
||||
if (select_loop->fd_events[fd] &&
|
||||
select_loop->fd_events[fd]->read_cb &&
|
||||
FD_ISSET(fd, &readfds))
|
||||
select_read_cb(fd, select_loop->fd_events[fd]);
|
||||
|
||||
if (select_loop->fd_events[fd] &&
|
||||
select_loop->fd_events[fd]->write_cb &&
|
||||
FD_ISSET(fd, &writefds))
|
||||
select_write_cb(fd, select_loop->fd_events[fd]);
|
||||
|
||||
if (select_loop->fd_events[fd] &&
|
||||
select_loop->fd_events[fd]->timeout_cb &&
|
||||
now > select_loop->fd_timeout_times[fd])
|
||||
select_timeout_cb(fd, select_loop->fd_events[fd]);
|
||||
|
||||
i = fd;
|
||||
if (select_loop->timeout_events[i] &&
|
||||
select_loop->timeout_events[i]->timeout_cb &&
|
||||
now > select_loop->timeout_times[i])
|
||||
select_timeout_cb(-1, select_loop->timeout_events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
select_eventloop_run(getdns_eventloop *loop)
|
||||
{
|
||||
_getdns_select_eventloop *select_loop = (_getdns_select_eventloop *)loop;
|
||||
size_t i;
|
||||
|
||||
if (!loop)
|
||||
return;
|
||||
|
||||
i = 0;
|
||||
while (i < MAX_TIMEOUTS) {
|
||||
if (select_loop->fd_events[i] || select_loop->timeout_events[i]) {
|
||||
select_eventloop_run_once(loop, 1);
|
||||
i = 0;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_getdns_select_eventloop_init(_getdns_select_eventloop *loop)
|
||||
{
|
||||
static getdns_eventloop_vmt select_eventloop_vmt = {
|
||||
select_eventloop_cleanup,
|
||||
select_eventloop_schedule,
|
||||
select_eventloop_clear,
|
||||
select_eventloop_run,
|
||||
select_eventloop_run_once
|
||||
};
|
||||
|
||||
(void) memset(loop, 0, sizeof(_getdns_select_eventloop));
|
||||
loop->loop.vmt = &select_eventloop_vmt;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* \file select_eventloop.h
|
||||
* @brief Build in default eventloop extension that uses select.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2013, NLNet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SELECT_EVENTLOOP_H_
|
||||
#define SELECT_EVENTLOOP_H_
|
||||
#include "config.h"
|
||||
#include "getdns/getdns.h"
|
||||
#include "getdns/getdns_extra.h"
|
||||
|
||||
/* No more than select's capability queries can be outstanding,
|
||||
* The number of outstanding timeouts should be less or equal then
|
||||
* the number of outstanding queries, so MAX_TIMEOUTS equal to
|
||||
* FD_SETSIZE should be safe.
|
||||
*/
|
||||
#define MAX_TIMEOUTS FD_SETSIZE
|
||||
|
||||
/* Eventloop based on select */
|
||||
typedef struct _getdns_select_eventloop {
|
||||
getdns_eventloop loop;
|
||||
getdns_eventloop_event *fd_events[FD_SETSIZE];
|
||||
uint64_t fd_timeout_times[FD_SETSIZE];
|
||||
getdns_eventloop_event *timeout_events[MAX_TIMEOUTS];
|
||||
uint64_t timeout_times[MAX_TIMEOUTS];
|
||||
} _getdns_select_eventloop;
|
||||
|
||||
|
||||
void
|
||||
_getdns_select_eventloop_init(_getdns_select_eventloop *loop);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue