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;
+ }
}
}