libevent & libev following new extension scheme

This commit is contained in:
Willem Toorop 2014-10-09 01:18:53 +02:00
parent 1f203485e2
commit b3b634a2f5
6 changed files with 294 additions and 249 deletions

View File

@ -759,11 +759,11 @@ getdns_context_request_count_changed(getdns_context *context, uint32_t prev_rc)
return;
if (context->outbound_requests->count)
context->extension->functions->schedule_read(
context->extension->vmt->schedule_read(
context->extension, ub_fd(context->unbound_ctx),
TIMEOUT_FOREVER, &context->ub_event);
else
context->extension->functions->clear_read(
context->extension->vmt->clear_read(
context->extension, &context->ub_event);
}
@ -1886,7 +1886,7 @@ getdns_context_detach_eventloop(struct getdns_context* context)
context->processing = 1;
/* cancel all outstanding requests */
cancel_outstanding_requests(context, 1);
r = context->extension->functions->cleanup(context->extension);
r = context->extension->vmt->cleanup(context->extension);
if (r == GETDNS_RETURN_GOOD) {
context->extension = &context->mini_event.loop;
r = getdns_mini_event_init(context, &context->mini_event);
@ -1924,7 +1924,7 @@ getdns_context_schedule_timeout(getdns_context *context, uint64_t timeout,
el_ev->timeout_cb = callback;
el_ev->ev = NULL;
return context->extension->functions->schedule_timeout(
return context->extension->vmt->schedule_timeout(
context->extension, timeout, el_ev);
}
@ -1937,7 +1937,7 @@ getdns_context_clear_timeout(getdns_context* context,
RETURN_IF_NULL(el_ev->timeout_cb, GETDNS_RETURN_GOOD);
if (el_ev->timeout_cb) {
context->extension->functions->clear_timeout(
context->extension->vmt->clear_timeout(
context->extension, el_ev);
el_ev->timeout_cb = NULL;
}
@ -2110,4 +2110,10 @@ getdns_context_local_namespace_resolve(getdns_dns_req* req,
}
struct mem_funcs *
priv_getdns_context_mf(getdns_context *context)
{
return &context->mf;
}
/* context.c */

View File

@ -37,6 +37,7 @@
#include <stdio.h>
#include "getdns/getdns_ext_libev.h"
#include "config.h"
#include "types-internal.h"
#ifdef HAVE_LIBEV_EV_H
#include <libev/ev.h>
@ -46,119 +47,138 @@
#define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code;
/* extension info */
struct getdns_libev_data {
struct ev_loop* loop;
struct ev_io* poll_handle;
};
typedef struct getdns_libev {
getdns_eventloop_vmt *vmt;
struct ev_loop *loop;
struct mem_funcs mf;
} getdns_libev;
static void
request_count_changed(uint32_t request_count, struct getdns_libev_data *ev_data) {
if (request_count > 0) {
ev_io_start(ev_data->loop, ev_data->poll_handle);
} else {
ev_io_stop(ev_data->loop, ev_data->poll_handle);
}
}
static getdns_return_t getdns_libev_cleanup(getdns_eventloop *loop);
static getdns_return_t getdns_libev_schedule_read(getdns_eventloop *loop,
int fd, uint64_t timeout, getdns_eventloop_event *ev);
static getdns_return_t getdns_libev_schedule_timeout
(getdns_eventloop *loop, uint64_t timeout, getdns_eventloop_event *ev);
static getdns_return_t getdns_libev_clear_event
(getdns_eventloop *loop, getdns_eventloop_event *ev);
/* lib ev callbacks */
static void
getdns_libev_cb(struct ev_loop *loop, struct ev_io *handle, int revents) {
struct getdns_context* context = (struct getdns_context*) handle->data;
if (getdns_context_process_async(context) == GETDNS_RETURN_BAD_CONTEXT) {
// context destroyed
return;
}
uint32_t rc = getdns_context_get_num_pending_requests(context, NULL);
struct getdns_libev_data* ev_data =
(struct getdns_libev_data*) getdns_context_get_extension_data(context);
request_count_changed(rc, ev_data);
}
static void
getdns_libev_timeout_cb(struct ev_loop *loop, struct ev_timer* handle, int status) {
getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*) handle->data;
timeout_data->callback(timeout_data->userarg);
}
/* getdns extension functions */
static getdns_return_t
getdns_libev_request_count_changed(struct getdns_context* context,
uint32_t request_count, void* eventloop_data) {
struct getdns_libev_data *ev_data = (struct getdns_libev_data*) eventloop_data;
request_count_changed(request_count, ev_data);
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_libev_cleanup(struct getdns_context* context, void* data) {
struct getdns_libev_data *ev_data = (struct getdns_libev_data*) data;
ev_io_stop(ev_data->loop, ev_data->poll_handle);
free(ev_data->poll_handle);
free(ev_data);
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_libev_schedule_timeout(struct getdns_context* context,
void* eventloop_data, uint64_t timeout,
getdns_timeout_data_t* timeout_data)
{
struct ev_timer *timer;
struct getdns_libev_data* ev_data = (struct getdns_libev_data*) eventloop_data;
ev_tstamp to = timeout;
to /= 1000;
timer = (struct ev_timer*) malloc(sizeof(struct ev_timer));
ev_timer_init(timer, getdns_libev_timeout_cb, to, 0);
timer->data = timeout_data;
timeout_data->extension_timer = timer;
ev_timer_start(ev_data->loop, timer);
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_libev_clear_timeout(struct getdns_context* context,
void* eventloop_data, void* eventloop_timer) {
struct ev_timer* timer = (struct ev_timer*) eventloop_timer;
struct getdns_libev_data* ev_data = (struct getdns_libev_data*) eventloop_data;
ev_timer_stop(ev_data->loop, timer);
free(timer);
return GETDNS_RETURN_GOOD;
}
static getdns_eventloop_extension LIBEV_EXT = {
static getdns_eventloop_vmt getdns_libev_vmt = {
getdns_libev_cleanup,
getdns_libev_schedule_read,
getdns_libev_clear_event,
getdns_libev_schedule_timeout,
getdns_libev_clear_timeout,
getdns_libev_request_count_changed
getdns_libev_clear_event,
};
/*
* getdns_extension_set_libev_loop
*
*/
getdns_return_t
getdns_extension_set_libev_loop(struct getdns_context *context,
getdns_extension_set_libev_loop(getdns_context *context,
struct ev_loop *loop)
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(loop, GETDNS_RETURN_INVALID_PARAMETER);
/* TODO: cleanup current extension base */
getdns_return_t r = getdns_extension_detach_eventloop(context);
if (r != GETDNS_RETURN_GOOD) {
return r;
}
struct getdns_libev_data* ev_data = (struct getdns_libev_data*) malloc(sizeof(struct getdns_libev_data));
if (!ev_data) {
return GETDNS_RETURN_MEMORY_ERROR;
}
int fd = getdns_context_fd(context);
ev_data->poll_handle = (struct ev_io*) malloc(sizeof(struct ev_io));
ev_io_init(ev_data->poll_handle, getdns_libev_cb, fd, EV_READ);
ev_data->loop = loop;
getdns_libev *ext;
getdns_return_t r;
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
RETURN_IF_NULL(loop, GETDNS_RETURN_INVALID_PARAMETER);
if ((r = getdns_context_detach_eventloop(context)))
return r;
ext = GETDNS_MALLOC(*priv_getdns_context_mf(context), getdns_libev);
ext->vmt = &getdns_libev_vmt;
ext->loop = loop;
ext->mf = *priv_getdns_context_mf(context);
return getdns_context_set_eventloop(context, (getdns_eventloop *)&ext);
}
static getdns_return_t
getdns_libev_cleanup(getdns_eventloop *loop)
{
getdns_libev *ext = (getdns_libev *)loop;
GETDNS_FREE(ext->mf, ext);
return GETDNS_RETURN_GOOD;
}
static void
getdns_libev_read_cb(struct ev_loop *l, struct ev_io *io, int revents)
{
getdns_eventloop_event *el_ev = (getdns_eventloop_event *)io->data;
assert(el_ev->read_cb);
el_ev->read_cb(el_ev->userarg);
}
static void
getdns_libev_timeout_cb(struct ev_loop *l, struct ev_timer *timer, int revent)
{
getdns_eventloop_event *el_ev = (getdns_eventloop_event *)timer->data;
assert(el_ev->timeout_cb);
el_ev->timeout_cb(el_ev->userarg);
}
typedef struct io_timer {
ev_io io;
ev_timer timer;
} io_timer;
static getdns_return_t
getdns_libev_schedule_read(getdns_eventloop *loop,
int fd, uint64_t timeout, getdns_eventloop_event *el_ev)
{
getdns_libev *ext = (getdns_libev *)loop;
io_timer *my_ev;
ev_io *my_io;
ev_timer *my_timer;
ev_tstamp to = ((ev_tstamp)timeout) / 1000;
if (fd < 0) el_ev->read_cb = NULL;
if (timeout == TIMEOUT_FOREVER) el_ev->timeout_cb = NULL;
if (!el_ev->read_cb && !el_ev->timeout_cb)
return GETDNS_RETURN_GOOD; /* Nothing to schedule */
if (!(my_ev = GETDNS_MALLOC(ext->mf, io_timer)))
return GETDNS_RETURN_MEMORY_ERROR;
el_ev->ev = my_ev;
if (el_ev->read_cb) {
my_io = &my_ev->io;
my_io->data = el_ev;
ev_io_init(my_io, getdns_libev_read_cb, fd, EV_READ);
ev_io_start(ext->loop, &my_ev->io);
}
if (el_ev->timeout_cb) {
my_timer = &my_ev->timer;
my_timer->data = el_ev;
ev_timer_init(my_timer, getdns_libev_timeout_cb, to, 0);
ev_timer_start(ext->loop, &my_ev->timer);
}
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_libev_schedule_timeout(getdns_eventloop *loop,
uint64_t timeout, getdns_eventloop_event *el_ev)
{
return getdns_libev_schedule_read(loop, -1, timeout, el_ev);
}
static getdns_return_t
getdns_libev_clear_event(getdns_eventloop *loop,
getdns_eventloop_event *el_ev)
{
getdns_libev *ext = (getdns_libev *)loop;
io_timer *my_ev = (io_timer *)el_ev->ev;
assert(my_ev);
if (el_ev->read_cb)
ev_io_stop(ext->loop, &my_ev->io);
if (el_ev->timeout_cb)
ev_timer_stop(ext->loop, &my_ev->timer);
GETDNS_FREE(ext->mf, el_ev->ev);
el_ev->ev = NULL;
return GETDNS_RETURN_GOOD;
}
ev_data->poll_handle->data = context;
return getdns_extension_set_eventloop(context, &LIBEV_EXT, ev_data);
} /* getdns_extension_set_libev_loop */

View File

@ -36,6 +36,7 @@
#include <sys/time.h>
#include "getdns/getdns_ext_libevent.h"
#include "config.h"
#include "types-internal.h"
#ifdef HAVE_EVENT2_EVENT_H
# include <event2/event.h>
@ -59,132 +60,139 @@ static struct event *
event_new(struct event_base *b, evutil_socket_t fd, short ev, void* cb, void *arg)
{
struct event* e = (struct event*)calloc(1, sizeof(struct event));
if(!e) return NULL;
if (!e) return NULL;
event_set(e, fd, ev, cb, arg);
event_base_set(b, e);
return e;
}
static struct event_base *
event_get_base(const struct event *ev)
{
return ev->base;
}
static evutil_socket_t df
event_get_fd(const struct event *ev)
{
return ev->fd;
}
#endif /* no event2 */
/* extension info */
struct event_data {
struct event* event;
struct event_base* event_base;
};
typedef struct getdns_libevent {
getdns_eventloop_vmt *vmt;
struct event_base *base;
struct mem_funcs mf;
} getdns_libevent;
static void
request_count_changed(uint32_t request_count, struct event_data *ev_data) {
if (request_count > 0) {
event_add(ev_data->event, NULL);
} else {
event_del(ev_data->event);
}
}
static getdns_return_t getdns_libevent_cleanup(getdns_eventloop *loop);
static getdns_return_t getdns_libevent_schedule_read(getdns_eventloop *loop,
int fd, uint64_t timeout, getdns_eventloop_event *ev);
static getdns_return_t getdns_libevent_schedule_timeout
(getdns_eventloop *loop, uint64_t timeout, getdns_eventloop_event *ev);
static getdns_return_t getdns_libevent_clear_event
(getdns_eventloop *loop, getdns_eventloop_event *ev);
/* lib event callbacks */
static void
getdns_libevent_cb(evutil_socket_t fd, short what, void *userarg) {
struct getdns_context* context = (struct getdns_context*) userarg;
if (getdns_context_process_async(context) == GETDNS_RETURN_BAD_CONTEXT) {
// context destroyed
return;
}
uint32_t rc = getdns_context_get_num_pending_requests(context, NULL);
struct event_data* ev_data =
(struct event_data*) getdns_context_get_extension_data(context);
request_count_changed(rc, ev_data);
}
static void
getdns_libevent_timeout_cb(evutil_socket_t fd, short what, void* userarg) {
getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*) userarg;
timeout_data->callback(timeout_data->userarg);
}
/* getdns extension functions */
static getdns_return_t
getdns_libevent_request_count_changed(struct getdns_context* context,
uint32_t request_count, void* eventloop_data) {
struct event_data *edata = (struct event_data*) eventloop_data;
request_count_changed(request_count, edata);
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_libevent_cleanup(struct getdns_context* context, void* data) {
struct event_data *edata = (struct event_data*) data;
event_del(edata->event);
event_free(edata->event);
free(edata);
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_libevent_schedule_timeout(struct getdns_context* context,
void* eventloop_data, uint64_t timeout,
getdns_timeout_data_t* timeout_data)
{
struct timeval tv;
struct event* ev = NULL;
struct event_data* ev_data = (struct event_data*) eventloop_data;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
ev = evtimer_new(ev_data->event_base, getdns_libevent_timeout_cb, timeout_data);
timeout_data->extension_timer = ev;
evtimer_add(ev, &tv);
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_libevent_clear_timeout(struct getdns_context* context,
void* eventloop_data, void* eventloop_timer) {
struct event* ev = (struct event*) eventloop_timer;
event_del(ev);
event_free(ev);
return GETDNS_RETURN_GOOD;
}
static getdns_eventloop_extension LIBEVENT_EXT = {
static getdns_eventloop_vmt getdns_libevent_vmt = {
getdns_libevent_cleanup,
getdns_libevent_schedule_read,
getdns_libevent_clear_event,
getdns_libevent_schedule_timeout,
getdns_libevent_clear_timeout,
getdns_libevent_request_count_changed
getdns_libevent_clear_event,
};
/*
* getdns_extension_set_libevent_base
*
*/
getdns_return_t
getdns_extension_set_libevent_base(struct getdns_context *context,
struct event_base * this_event_base)
getdns_extension_set_libevent_base(getdns_context *context,
struct event_base *base)
{
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
RETURN_IF_NULL(this_event_base, GETDNS_RETURN_INVALID_PARAMETER);
/* TODO: cleanup current extension base */
getdns_return_t r = getdns_extension_detach_eventloop(context);
if (r != GETDNS_RETURN_GOOD) {
return r;
}
int fd = getdns_context_fd(context);
struct event* getdns_event = event_new(this_event_base, fd, EV_READ | EV_PERSIST, getdns_libevent_cb, context);
if (!getdns_event) {
return GETDNS_RETURN_GENERIC_ERROR;
}
getdns_libevent *ext;
getdns_return_t r;
/* TODO: use context functs? */
struct event_data* ev_data = (struct event_data*) malloc(sizeof(struct event_data));
if (!ev_data) {
/* cleanup */
event_del(getdns_event);
event_free(getdns_event);
RETURN_IF_NULL(context, GETDNS_RETURN_BAD_CONTEXT);
RETURN_IF_NULL(base, GETDNS_RETURN_INVALID_PARAMETER);
if ((r = getdns_context_detach_eventloop(context)))
return r;
ext = GETDNS_MALLOC(*priv_getdns_context_mf(context), getdns_libevent);
ext->vmt = &getdns_libevent_vmt;
ext->base = base;
ext->mf = *priv_getdns_context_mf(context);
return getdns_context_set_eventloop(context, (getdns_eventloop *)&ext);
}
static getdns_return_t
getdns_libevent_cleanup(getdns_eventloop *loop)
{
getdns_libevent *ext = (getdns_libevent *)loop;
GETDNS_FREE(ext->mf, ext);
return GETDNS_RETURN_GOOD;
}
static void
getdns_libevent_callback(evutil_socket_t fd, short bits, void *arg)
{
getdns_eventloop_event *el_ev = (getdns_eventloop_event *)arg;
if (bits & EV_READ) {
assert(el_ev->read_cb);
el_ev->read_cb(el_ev->userarg);
} else if (bits & EV_TIMEOUT) {
assert(el_ev->timeout_cb);
el_ev->timeout_cb(el_ev->userarg);
} else
assert(ASSERT_UNREACHABLE);
}
static getdns_return_t
getdns_libevent_schedule_read(getdns_eventloop *loop,
int fd, uint64_t timeout, getdns_eventloop_event *el_ev)
{
getdns_libevent *ext = (getdns_libevent *)loop;
struct event *my_ev;
struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
short bits = ((fd >= 0 && el_ev->read_cb ? EV_READ|EV_PERSIST : 0) |
(timeout != TIMEOUT_FOREVER && el_ev->timeout_cb ? EV_TIMEOUT : 0));
if (!bits)
return GETDNS_RETURN_GOOD; /* Nothing to schedule */
if (!(my_ev = event_new(
ext->base, fd, bits, getdns_libevent_callback, el_ev)))
return GETDNS_RETURN_MEMORY_ERROR;
el_ev->ev = my_ev;
if (event_add(my_ev,
(timeout != TIMEOUT_FOREVER && el_ev->timeout_cb ? &tv : NULL)))
goto error;
return GETDNS_RETURN_GOOD;
error:
event_free(my_ev);
el_ev->ev = NULL;
return GETDNS_RETURN_GENERIC_ERROR;
}
ev_data->event = getdns_event;
ev_data->event_base = this_event_base;
return getdns_extension_set_eventloop(context, &LIBEVENT_EXT, ev_data);
} /* getdns_extension_set_libevent_base */
}
static getdns_return_t
getdns_libevent_schedule_timeout(getdns_eventloop *loop,
uint64_t timeout, getdns_eventloop_event *el_ev)
{
return getdns_libevent_schedule_read(loop, -1, timeout, el_ev);
}
static getdns_return_t
getdns_libevent_clear_event(getdns_eventloop *loop,
getdns_eventloop_event *el_ev)
{
assert(el_ev->ev);
if (event_del(el_ev->ev) != 0)
return GETDNS_RETURN_GENERIC_ERROR;
event_free(el_ev->ev);
el_ev->ev = NULL;
return GETDNS_RETURN_GOOD;
}

View File

@ -49,7 +49,7 @@ static getdns_return_t getdns_mini_event_schedule_timeout
static getdns_return_t getdns_mini_event_clear_event
(getdns_eventloop *loop, getdns_eventloop_event *ev);
static getdns_eventloop_functions getdns_mini_event_functions = {
static getdns_eventloop_vmt getdns_mini_event_vmt = {
getdns_mini_event_cleanup,
getdns_mini_event_schedule_read,
getdns_mini_event_clear_event,
@ -63,7 +63,7 @@ getdns_mini_event_init(getdns_context *context, getdns_mini_event *ext)
if (!context) return GETDNS_RETURN_BAD_CONTEXT;
if (!ext) return GETDNS_RETURN_INVALID_PARAMETER;
ext->loop.functions = &getdns_mini_event_functions;
ext->loop.vmt = &getdns_mini_event_vmt;
ext->base = getdns_event_init(&ext->time_secs, &ext->time_tv);
if (!ext->base)
return GETDNS_RETURN_MEMORY_ERROR;
@ -86,7 +86,7 @@ void
getdns_mini_event_destroy(getdns_mini_event *ext)
{
if (ext) {
ext->loop.functions->cleanup(&ext->loop);
ext->loop.vmt->cleanup(&ext->loop);
GETDNS_FREE(ext->mf, ext);
}
}
@ -158,17 +158,25 @@ getdns_mini_event_schedule_read(getdns_eventloop *loop,
if (!bits)
return GETDNS_RETURN_GOOD; /* Nothing to schedule */
my_ev = GETDNS_MALLOC(ext->mf, struct getdns_event);
if (!(my_ev = GETDNS_MALLOC(ext->mf, struct getdns_event)))
return GETDNS_RETURN_MEMORY_ERROR;
el_ev->ev = my_ev;
getdns_event_set(my_ev, fd, bits, getdns_mini_event_callback, el_ev);
if (getdns_mini_event_settime(ext))
return GETDNS_RETURN_GENERIC_ERROR;
goto error;
(void) getdns_event_base_set(ext->base, my_ev);
if (getdns_event_add(my_ev, &tv))
return GETDNS_RETURN_GENERIC_ERROR;
if (getdns_event_add(my_ev, (
timeout != TIMEOUT_FOREVER && el_ev->timeout_cb ? &tv : NULL)))
goto error;
return GETDNS_RETURN_GOOD;
error:
GETDNS_FREE(ext->mf, my_ev);
el_ev->ev = NULL;
return GETDNS_RETURN_GENERIC_ERROR;
}
static getdns_return_t

View File

@ -81,9 +81,9 @@ typedef struct getdns_eventloop_event {
void *ev;
} getdns_eventloop_event;
typedef struct getdns_eventloop_functions getdns_eventloop_functions;
typedef struct getdns_eventloop_vmt getdns_eventloop_vmt;
typedef struct getdns_eventloop {
getdns_eventloop_functions *functions;
getdns_eventloop_vmt *vmt;
} getdns_eventloop;
/* Call the extension to clean up data allocated on initialization. */
@ -118,7 +118,8 @@ typedef getdns_return_t (*getdns_eventloop_schedule_timeout)
typedef getdns_return_t (*getdns_eventloop_clear_timeout)
(getdns_eventloop *loop, getdns_eventloop_event *ev);
struct getdns_eventloop_functions {
/* Virtual Method Table */
struct getdns_eventloop_vmt {
getdns_eventloop_cleanup cleanup;
getdns_eventloop_schedule_read schedule_read;
getdns_eventloop_clear_read clear_read;

View File

@ -125,6 +125,9 @@ struct mem_funcs {
mf_union mf;
};
struct mem_funcs *
priv_getdns_context_mf(getdns_context *context);
typedef enum network_req_state_enum
{
NET_REQ_NOT_SENT,
@ -248,7 +251,6 @@ getdns_dns_req *dns_req_new(struct getdns_context *context,
void dns_req_free(getdns_dns_req * req);
#endif
/* types-internal.h */