Author: brane Date: Sat Jul 19 19:50:15 2025 New Revision: 1927337 URL: http://svn.apache.org/viewvc?rev=1927337&view=rev Log: Un the Unbound resolver, don't poll the resolver context unless we have actual queries in flight.
* src/resolve.c: Reorder includes so that our headers always come last. (resolve_context): New struct. Contains the Unbound context and a counter. (create_resolve_context): Allocate a new resolve_context and properly clean it up on error. (resolve_callback): Decrement the Unbound task counter. (resolve_address_async): Increment the Unbound task counter. (run_async_resolver_loop): Do not poll if there are no Unbound tasks. Modified: serf/trunk/src/resolve.c Modified: serf/trunk/src/resolve.c URL: http://svn.apache.org/viewvc/serf/trunk/src/resolve.c?rev=1927337&r1=1927336&r2=1927337&view=diff ============================================================================== --- serf/trunk/src/resolve.c (original) +++ serf/trunk/src/resolve.c Sat Jul 19 19:50:15 2025 @@ -19,24 +19,24 @@ */ #include <apr.h> + +/* This will the headers needed for inet_ntop and related structs. + On Windows, we'll always get <Winsock2.h> from <apr.h>. */ +#if APR_HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if APR_HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + #include <apr_errno.h> #include <apr_pools.h> +#include <apr_atomic.h> #include <apr_network_io.h> #include <apr_thread_mutex.h> #include <apr_thread_pool.h> -/* This will include <netinet/in.h> and/or <arpa/inet.h>, which we'll - use for logging the resolver results. On Windows, we'll always get - <Winsock2.h> from <apr.h>. */ -#define APR_WANT_BYTEFUNC -#include <apr_want.h> - -#include "serf.h" -#include "serf_private.h" - - -#define HAVE_ASYNC_RESOLVER (SERF_HAVE_ASYNC_RESOLVER || APR_HAS_THREADS) - +/* Third-party resolver headers. */ #if SERF_HAVE_ASYNC_RESOLVER #if SERF_HAVE_UNBOUND #include <unbound.h> @@ -47,6 +47,12 @@ #endif /* SERF_HAVE_UNBOUND */ #endif +#include "serf.h" +#include "serf_private.h" + + +#define HAVE_ASYNC_RESOLVER (SERF_HAVE_ASYNC_RESOLVER || APR_HAS_THREADS) + /* * FIXME: EXPERIMENTAL * TODO: @@ -229,39 +235,48 @@ static apr_status_t err_to_status(enum u } +struct resolve_context +{ + struct ub_ctx *ub_ctx; + volatile apr_uint32_t tasks; +}; + static apr_status_t cleanup_resolve_context(void *baton) { - struct ub_ctx *const resolve_context = baton; - ub_ctx_delete(resolve_context); + struct resolve_context *const rctx = baton; + ub_ctx_delete(rctx->ub_ctx); return APR_SUCCESS; } static apr_status_t create_resolve_context(serf_context_t *ctx) { + struct resolve_context *const rctx = apr_palloc(ctx->pool, sizeof(*rctx)); int err; - struct ub_ctx *const resolve_context = ub_ctx_create(); - if (!resolve_context) + + rctx->ub_ctx = ub_ctx_create(); + rctx->tasks = 0; + if (!rctx->ub_ctx) return APR_ENOMEM; - err = ub_ctx_resolvconf(resolve_context, NULL); + err = ub_ctx_resolvconf(rctx->ub_ctx, NULL); if (!err) - err = ub_ctx_hosts(resolve_context, NULL); + err = ub_ctx_hosts(rctx->ub_ctx, NULL); if (!err) - err = ub_ctx_async(resolve_context, true); + err = ub_ctx_async(rctx->ub_ctx, true); if (err) { const apr_status_t status = err_to_status(err); /* TODO: Error callback */ serf__log(LOGLVL_ERROR, LOGCOMP_CONN, __FILE__, ctx->config, "unbound ctx init: %s\n", ub_strerror(err)); + cleanup_resolve_context(rctx); return status; } - ctx->resolve_context = resolve_context; + ctx->resolve_context = rctx; /* pre-cleanup because the live resolve tasks contain subpools of the context pool and must be canceled before their pools go away. */ - apr_pool_pre_cleanup_register(ctx->pool, resolve_context, - cleanup_resolve_context); + apr_pool_pre_cleanup_register(ctx->pool, rctx, cleanup_resolve_context); return APR_SUCCESS; } @@ -283,6 +298,9 @@ static void resolve_callback(void* baton resolve_task_t *const task = baton; apr_status_t status = err_to_status(err); + struct resolve_context *const rctx = task->ctx->resolve_context; + apr_atomic_dec32(&rctx->tasks); + if (err) { /* TODO: Error callback */ serf__log(LOGLVL_ERROR, LOGCOMP_CONN, __FILE__, task->ctx->config, @@ -366,7 +384,7 @@ static apr_status_t resolve_address_asyn apr_pool_t *resolve_pool, apr_pool_t *scratch_pool) { - struct ub_ctx *const resolve_context = ctx->resolve_context; + struct resolve_context *const rctx = ctx->resolve_context; resolve_task_t *const task = apr_palloc(resolve_pool, sizeof(*task)); apr_status_t status = APR_SUCCESS; int err; @@ -378,7 +396,7 @@ static apr_status_t resolve_address_asyn task->resolve_pool = resolve_pool; /* FIXME: We should resolve both RRType 1 (A) and RRType 28 (AAAA). */ - if ((err = ub_resolve_async(resolve_context, host_info.hostname, + if ((err = ub_resolve_async(rctx->ub_ctx, host_info.hostname, 1, /* rrtype: IPv4 host address (A) */ 1, /* rrclass: IN(ternet) */ task, resolve_callback, NULL))) @@ -389,21 +407,28 @@ static apr_status_t resolve_address_asyn "unbound resolve start: %s\n", ub_strerror(err)); } + if (status == APR_SUCCESS) { + apr_atomic_inc32(&rctx->tasks); + } return status; } static apr_status_t run_async_resolver_loop(serf_context_t *ctx) { - struct ub_ctx *const resolve_context = ctx->resolve_context; + struct resolve_context *const rctx = ctx->resolve_context; - if (ub_poll(resolve_context)) { - const int err = ub_process(resolve_context); - if (err) { - const apr_status_t status = err_to_status(err); - /* TODO: Error callback */ - serf__log(LOGLVL_ERROR, LOGCOMP_CONN, __FILE__, ctx->config, - "unbound process: %s\n", ub_strerror(err)); - return status; + /* No need to poll if there are no in-flight tasks. */ + if (apr_atomic_read32(&rctx->tasks)) + { + if (ub_poll(rctx->ub_ctx)) { + const int err = ub_process(rctx->ub_ctx); + if (err) { + const apr_status_t status = err_to_status(err); + /* TODO: Error callback */ + serf__log(LOGLVL_ERROR, LOGCOMP_CONN, __FILE__, ctx->config, + "unbound process: %s\n", ub_strerror(err)); + return status; + } } }