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
|
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)),
|
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)
|
enable_tcp_fastopen="$enableval", enable_tcp_fastopen=yes)
|
||||||
if test "x$enable_tcp_fastopen" = xno; then
|
if test "x$enable_tcp_fastopen" = xno; then
|
||||||
|
@ -1076,8 +1101,6 @@ if test "$ac_cv_func_arc4random" = "no"; then
|
||||||
])
|
])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_DEFINE(USE_MINI_EVENT, 1, [Needed for sync stub resolver functions])
|
|
||||||
|
|
||||||
AC_TYPE_SIGNAL
|
AC_TYPE_SIGNAL
|
||||||
|
|
||||||
case `uname` in
|
case `uname` in
|
||||||
|
|
|
@ -65,6 +65,8 @@ EXTENSION_LIBUV_LDFLAGS=@EXTENSION_LIBUV_LDFLAGS@
|
||||||
|
|
||||||
C99COMPATFLAGS=@C99COMPATFLAGS@
|
C99COMPATFLAGS=@C99COMPATFLAGS@
|
||||||
|
|
||||||
|
DEFAULT_EVENTLOOP_OBJ=@DEFAULT_EVENTLOOP@.lo
|
||||||
|
|
||||||
GETDNS_OBJ=const-info.lo convert.lo dict.lo dnssec.lo general.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 \
|
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 \
|
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
|
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
|
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
|
$(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)
|
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.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols
|
$(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
|
test: all
|
||||||
cd test && $(MAKE) $@
|
cd test && $(MAKE) $@
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* \file default_eventloop.h
|
* \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_
|
#ifndef DEFAULT_EVENTLOOP_H_
|
||||||
#define DEFAULT_EVENTLOOP_H_
|
#define DEFAULT_EVENTLOOP_H_
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "getdns/getdns.h"
|
#ifdef USE_POLL_DEFAULT_EVENTLOOP
|
||||||
#include "getdns/getdns_extra.h"
|
#include "extension/poll_eventloop.h"
|
||||||
#include "util/uthash.h"
|
#define _getdns_default_eventloop _getdns_poll_eventloop
|
||||||
|
#define _getdns_default_eventloop_init _getdns_poll_eventloop_init
|
||||||
/* Eventloop based on poll */
|
#else
|
||||||
|
#include "extension/select_eventloop.h"
|
||||||
typedef struct _getdns_eventloop_info {
|
#define _getdns_default_eventloop _getdns_select_eventloop
|
||||||
int id;
|
#define _getdns_default_eventloop_init _getdns_select_eventloop_init
|
||||||
getdns_eventloop_event *event;
|
#endif
|
||||||
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);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -27,15 +27,20 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifndef USE_WINSOCK
|
#ifdef HAVE_SYS_POLL_H
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#else
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_SYS_RESOURCE_H
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include "extension/default_eventloop.h"
|
#endif
|
||||||
|
#include "extension/poll_eventloop.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "types-internal.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;
|
_getdns_eventloop_info* ev;
|
||||||
|
|
||||||
|
@ -44,9 +49,10 @@ _getdns_eventloop_info *find_event(_getdns_eventloop_info** events, int id)
|
||||||
return ev;
|
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));
|
_getdns_eventloop_info* myevent = calloc(1, sizeof(_getdns_eventloop_info));
|
||||||
myevent->event = ev->event;
|
myevent->event = ev->event;
|
||||||
myevent->id = id;
|
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);
|
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);
|
HASH_DEL(*events, ev);
|
||||||
free(ev);
|
free(ev);
|
||||||
}
|
}
|
||||||
|
@ -77,30 +84,33 @@ static uint64_t get_now_plus(uint64_t amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
static getdns_return_t
|
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)
|
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;
|
size_t i;
|
||||||
|
|
||||||
DEBUG_SCHED( "%s(loop: %p, fd: %d, timeout: %"PRIu64", event: %p, max_fds: %d)\n"
|
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)
|
if (!loop || !event)
|
||||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
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"
|
DEBUG_SCHED( "ERROR: fd %d >= max_fds: %d!\n"
|
||||||
, fd, default_loop->max_fds);
|
, fd, poll_loop->max_fds);
|
||||||
return GETDNS_RETURN_GENERIC_ERROR;
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (fd >= 0 && !(event->read_cb || event->write_cb)) {
|
if (fd >= 0 && !(event->read_cb || event->write_cb)) {
|
||||||
DEBUG_SCHED("WARNING: fd event without "
|
DEBUG_SCHED("WARNING: fd event without "
|
||||||
"read or write cb!\n");
|
"read or write cb!\n");
|
||||||
fd = -1;
|
fd = -1;
|
||||||
}
|
}
|
||||||
if (fd >= 0) {
|
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 defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||||
if (fd_event) {
|
if (fd_event) {
|
||||||
if (fd_event->event == event) {
|
if (fd_event->event == event) {
|
||||||
|
@ -116,13 +126,13 @@ default_eventloop_schedule(getdns_eventloop *loop,
|
||||||
#endif
|
#endif
|
||||||
/* cleanup the old event if it exists */
|
/* cleanup the old event if it exists */
|
||||||
if (fd_event) {
|
if (fd_event) {
|
||||||
delete_event(&default_loop->fd_events, fd_event);
|
delete_event(&poll_loop->fd_events, fd_event);
|
||||||
}
|
}
|
||||||
_getdns_eventloop_info fd_ev;
|
_getdns_eventloop_info fd_ev;
|
||||||
event->ev = (void *) (intptr_t) (fd + 1);
|
event->ev = (void *) (intptr_t) (fd + 1);
|
||||||
fd_ev.event = event;
|
fd_ev.event = event;
|
||||||
fd_ev.timeout_time = get_now_plus(timeout);
|
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);
|
DEBUG_SCHED( "scheduled read/write at fd %d\n", fd);
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
|
@ -139,12 +149,12 @@ default_eventloop_schedule(getdns_eventloop *loop,
|
||||||
DEBUG_SCHED("ERROR: timeout event with write_cb! Clearing.\n");
|
DEBUG_SCHED("ERROR: timeout event with write_cb! Clearing.\n");
|
||||||
event->write_cb = NULL;
|
event->write_cb = NULL;
|
||||||
}
|
}
|
||||||
for (i = 0; i < default_loop->max_timeouts; i++) {
|
for (i = poll_loop->timeout_id + 1; i != poll_loop->timeout_id; i++) {
|
||||||
if (find_event(&default_loop->timeout_events, i) == NULL) {
|
if (find_event(&poll_loop->timeout_events, i) == NULL) {
|
||||||
_getdns_eventloop_info timeout_ev;
|
_getdns_eventloop_info timeout_ev;
|
||||||
timeout_ev.event = event;
|
timeout_ev.event = event;
|
||||||
timeout_ev.timeout_time = get_now_plus(timeout);
|
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);
|
event->ev = (void *) (intptr_t) (i + 1);
|
||||||
|
|
||||||
DEBUG_SCHED( "scheduled timeout at slot %d\n", (int)i);
|
DEBUG_SCHED( "scheduled timeout at slot %d\n", (int)i);
|
||||||
|
@ -156,9 +166,9 @@ default_eventloop_schedule(getdns_eventloop *loop,
|
||||||
}
|
}
|
||||||
|
|
||||||
static getdns_return_t
|
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;
|
ssize_t i;
|
||||||
|
|
||||||
if (!loop || !event)
|
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);
|
DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNC__, (void *)loop, (void *)event);
|
||||||
|
|
||||||
i = (intptr_t)event->ev - 1;
|
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;
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
if (event->timeout_cb && !event->read_cb && !event->write_cb) {
|
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 defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||||
if (timeout_event && timeout_event->event != event)
|
if (timeout_event && timeout_event->event != event)
|
||||||
DEBUG_SCHED( "ERROR: Different/wrong event present at "
|
DEBUG_SCHED( "ERROR: Different/wrong event present at "
|
||||||
|
@ -180,10 +194,10 @@ default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
if (timeout_event) {
|
if (timeout_event) {
|
||||||
delete_event(&default_loop->timeout_events, timeout_event);
|
delete_event(&poll_loop->timeout_events, timeout_event);
|
||||||
}
|
}
|
||||||
} else {
|
} 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 defined(SCHED_DEBUG) && SCHED_DEBUG
|
||||||
if (fd_event && fd_event->event != event)
|
if (fd_event && fd_event->event != event)
|
||||||
DEBUG_SCHED( "ERROR: Different/wrong event present at "
|
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);
|
, (void *)fd_event);
|
||||||
#endif
|
#endif
|
||||||
if (fd_event) {
|
if (fd_event) {
|
||||||
delete_event(&default_loop->fd_events, fd_event);
|
delete_event(&poll_loop->fd_events, fd_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event->ev = NULL;
|
event->ev = NULL;
|
||||||
|
@ -199,15 +213,15 @@ default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
default_eventloop_cleanup(getdns_eventloop *loop)
|
poll_eventloop_cleanup(getdns_eventloop *loop)
|
||||||
{
|
{
|
||||||
_getdns_default_eventloop *default_loop = (_getdns_default_eventloop *)loop;
|
_getdns_poll_eventloop *poll_loop = (_getdns_poll_eventloop *)loop;
|
||||||
HASH_CLEAR(hh, default_loop->fd_events);
|
HASH_CLEAR(hh, poll_loop->fd_events);
|
||||||
HASH_CLEAR(hh, default_loop->timeout_events);
|
HASH_CLEAR(hh, poll_loop->timeout_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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
|
#if !defined(SCHED_DEBUG) || !SCHED_DEBUG
|
||||||
(void)fd;
|
(void)fd;
|
||||||
|
@ -217,7 +231,7 @@ default_read_cb(int fd, getdns_eventloop_event *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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
|
#if !defined(SCHED_DEBUG) || !SCHED_DEBUG
|
||||||
(void)fd;
|
(void)fd;
|
||||||
|
@ -227,7 +241,7 @@ default_write_cb(int fd, getdns_eventloop_event *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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
|
#if !defined(SCHED_DEBUG) || !SCHED_DEBUG
|
||||||
(void)fd;
|
(void)fd;
|
||||||
|
@ -237,9 +251,9 @@ default_timeout_cb(int fd, getdns_eventloop_event *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
_getdns_eventloop_info *s, *tmp;
|
||||||
uint64_t now, timeout = TIMEOUT_FOREVER;
|
uint64_t now, timeout = TIMEOUT_FOREVER;
|
||||||
size_t i=0;
|
size_t i=0;
|
||||||
|
@ -254,7 +268,7 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
||||||
|
|
||||||
now = get_now_plus(0);
|
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)
|
if (now > s->timeout_time)
|
||||||
add_event(&timeout_timeout_cbs, s->id, s);
|
add_event(&timeout_timeout_cbs, s->id, s);
|
||||||
else if (s->timeout_time < timeout)
|
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) {
|
HASH_ITER(hh, timeout_timeout_cbs, s, tmp) {
|
||||||
getdns_eventloop_event* event = s->event;
|
getdns_eventloop_event* event = s->event;
|
||||||
delete_event(&timeout_timeout_cbs, s);
|
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
|
// 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 ||
|
if (s->event->read_cb ||
|
||||||
s->event->write_cb)
|
s->event->write_cb)
|
||||||
num_pfds++;
|
num_pfds++;
|
||||||
|
@ -281,7 +295,7 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
||||||
|
|
||||||
pfds = calloc(num_pfds, sizeof(struct pollfd));
|
pfds = calloc(num_pfds, sizeof(struct pollfd));
|
||||||
i = 0;
|
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) {
|
if (s->event->read_cb) {
|
||||||
pfds[i].fd = s->id;
|
pfds[i].fd = s->id;
|
||||||
pfds[i].events |= POLLIN;
|
pfds[i].events |= POLLIN;
|
||||||
|
@ -312,21 +326,21 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
||||||
now = get_now_plus(0);
|
now = get_now_plus(0);
|
||||||
for (i = 0; i < num_pfds; i++) {
|
for (i = 0; i < num_pfds; i++) {
|
||||||
int fd = pfds[i].fd;
|
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) {
|
if (fd_event && fd_event->event) {
|
||||||
getdns_eventloop_event* event = fd_event->event;
|
getdns_eventloop_event* event = fd_event->event;
|
||||||
if (event->read_cb &&
|
if (event->read_cb &&
|
||||||
(pfds[i].revents & POLLIN))
|
(pfds[i].revents & POLLIN))
|
||||||
default_read_cb(fd, event);
|
poll_read_cb(fd, event);
|
||||||
|
|
||||||
if (event->write_cb &&
|
if (event->write_cb &&
|
||||||
(pfds[i].revents & POLLOUT))
|
(pfds[i].revents & POLLOUT))
|
||||||
default_write_cb(fd, event);
|
poll_write_cb(fd, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pfds)
|
if (pfds)
|
||||||
free(pfds);
|
free(pfds);
|
||||||
HASH_ITER(hh, default_loop->fd_events, s, tmp) {
|
HASH_ITER(hh, poll_loop->fd_events, s, tmp) {
|
||||||
if (s->event &&
|
if (s->event &&
|
||||||
s->event->timeout_cb &&
|
s->event->timeout_cb &&
|
||||||
now > s->timeout_time)
|
now > s->timeout_time)
|
||||||
|
@ -338,9 +352,9 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking)
|
||||||
int fd = s->id;
|
int fd = s->id;
|
||||||
getdns_eventloop_event* event = s->event;
|
getdns_eventloop_event* event = s->event;
|
||||||
delete_event(&fd_timeout_cbs, s);
|
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 &&
|
if (s->event &&
|
||||||
s->event->timeout_cb &&
|
s->event->timeout_cb &&
|
||||||
now > s->timeout_time)
|
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) {
|
HASH_ITER(hh, timeout_timeout_cbs, s, tmp) {
|
||||||
getdns_eventloop_event* event = s->event;
|
getdns_eventloop_event* event = s->event;
|
||||||
delete_event(&timeout_timeout_cbs, s);
|
delete_event(&timeout_timeout_cbs, s);
|
||||||
default_timeout_cb(-1, event);
|
poll_timeout_cb(-1, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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)
|
if (!loop)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* keep going until all the events are cleared */
|
/* keep going until all the events are cleared */
|
||||||
while (default_loop->fd_events || default_loop->timeout_events) {
|
while (poll_loop->fd_events || poll_loop->timeout_events) {
|
||||||
default_eventloop_run_once(loop, 1);
|
poll_eventloop_run_once(loop, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_getdns_default_eventloop_init(_getdns_default_eventloop *loop)
|
_getdns_poll_eventloop_init(_getdns_poll_eventloop *loop)
|
||||||
{
|
{
|
||||||
static getdns_eventloop_vmt default_eventloop_vmt = {
|
#ifdef HAVE_GETRLIMIT
|
||||||
default_eventloop_cleanup,
|
struct rlimit rl;
|
||||||
default_eventloop_schedule,
|
#endif
|
||||||
default_eventloop_clear,
|
static getdns_eventloop_vmt poll_eventloop_vmt = {
|
||||||
default_eventloop_run,
|
poll_eventloop_cleanup,
|
||||||
default_eventloop_run_once
|
poll_eventloop_schedule,
|
||||||
|
poll_eventloop_clear,
|
||||||
|
poll_eventloop_run,
|
||||||
|
poll_eventloop_run_once
|
||||||
};
|
};
|
||||||
|
|
||||||
(void) memset(loop, 0, sizeof(_getdns_default_eventloop));
|
(void) memset(loop, 0, sizeof(_getdns_poll_eventloop));
|
||||||
loop->loop.vmt = &default_eventloop_vmt;
|
loop->loop.vmt = &poll_eventloop_vmt;
|
||||||
|
|
||||||
struct rlimit rl;
|
#ifdef HAVE_GETRLIMIT
|
||||||
if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
|
if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
|
||||||
loop->max_fds = rl.rlim_cur;
|
loop->max_fds = rl.rlim_cur;
|
||||||
loop->max_timeouts = loop->max_fds; /* this is somewhat arbitrary */
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG_SCHED("ERROR: could not obtain RLIMIT_NOFILE from getrlimit()\n");
|
DEBUG_SCHED("ERROR: could not obtain RLIMIT_NOFILE from getrlimit()\n");
|
||||||
|
#endif
|
||||||
loop->max_fds = 0;
|
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