Author: brane
Date: Fri Jul 18 13:45:41 2025
New Revision: 1927309

URL: http://svn.apache.org/viewvc?rev=1927309&view=rev
Log:
Add context-specific task cleanup when a context is destroyed.

* src/resolve.c: Update top-level TODO docstring.
  (do_init_work_queue): Renamed from init_work_queue().
  (init_work_queue): New; this is now the init-once entry point.
  (cleanup_resolve_tasks): New, pool cleanup function.
  (create_resolve_context): Call init_work_queue() and register the cleanup.
  (resolve_address_async): Call init_work_queue().
* test/test_context.c
  (async_resolve_cancel_callback,
   test_async_resolve_cancel): New test for the early cancellation path.
  (test_context): Register test_async_resolve_cancel.

Modified:
    serf/trunk/src/resolve.c
    serf/trunk/test/test_context.c

Modified: serf/trunk/src/resolve.c
URL: 
http://svn.apache.org/viewvc/serf/trunk/src/resolve.c?rev=1927309&r1=1927308&r2=1927309&view=diff
==============================================================================
--- serf/trunk/src/resolve.c (original)
+++ serf/trunk/src/resolve.c Fri Jul 18 13:45:41 2025
@@ -50,10 +50,6 @@
 /*
  * FIXME: EXPERIMENTAL
  * TODO:
- *  - Add cleanup function for in-flight resolve tasks if their owning
- *    context is destroyed. This function should be called from the
- *    context's pool cleanup handler.
- *
  *  - Wake the poll/select in serf_context_run() when new resolve
  *    results are available.
  *
@@ -424,9 +420,10 @@ static apr_status_t run_async_resolver_l
 #define MAX_WORK_QUEUE_THREADS 50
 static apr_pool_t *work_pool = NULL;
 static apr_thread_pool_t *work_queue = NULL;
-static apr_status_t init_work_queue(void *baton)
+
+static apr_status_t do_init_work_queue(void *baton)
 {
-    serf_context_t *ctx = baton;
+    serf_context_t *const ctx = baton;
     apr_status_t status;
 
     apr_pool_create(&work_pool, NULL);
@@ -440,11 +437,29 @@ static apr_status_t init_work_queue(void
     return status;
 }
 
+static apr_status_t init_work_queue(serf_context_t *ctx)
+{
+    SERF__DECLARE_STATIC_INIT_ONCE_CONTEXT(init_ctx);
+    return serf__init_once(&init_ctx, do_init_work_queue, ctx);
+}
+
+
+static apr_status_t cleanup_resolve_tasks(void *baton)
+{
+    /* baton is serf_context_t */
+    return apr_thread_pool_tasks_cancel(work_queue, baton);
+}
 
 static apr_status_t create_resolve_context(serf_context_t *ctx)
 {
+    apr_status_t status;
+
     ctx->resolve_context = NULL;
-    return APR_SUCCESS;
+    status = init_work_queue(ctx);
+    if (status == APR_SUCCESS)
+        apr_pool_pre_cleanup_register(ctx->pool, ctx, cleanup_resolve_tasks);
+
+    return status;
 }
 
 
@@ -507,10 +522,7 @@ static apr_status_t resolve_address_asyn
                                           apr_pool_t *scratch_pool)
 {
     resolve_task_t *task;
-    apr_status_t status;
-    SERF__DECLARE_STATIC_INIT_ONCE_CONTEXT(init_ctx);
-
-    status = serf__init_once(&init_ctx, init_work_queue, ctx);
+    apr_status_t status = init_work_queue(ctx);
     if (status)
         return status;
 

Modified: serf/trunk/test/test_context.c
URL: 
http://svn.apache.org/viewvc/serf/trunk/test/test_context.c?rev=1927309&r1=1927308&r2=1927309&view=diff
==============================================================================
--- serf/trunk/test/test_context.c (original)
+++ serf/trunk/test/test_context.c Fri Jul 18 13:45:41 2025
@@ -1058,6 +1058,44 @@ static void test_async_resolve(CuTest *t
                                                 handler_ctx, tb->pool);
 }
 
+static void async_resolve_cancel_callback(serf_context_t *ctx,
+                                          void *resolved_baton,
+                                          apr_sockaddr_t *host_address,
+                                          apr_status_t status,
+                                          apr_pool_t *scratch_pool)
+{
+    *(int*)resolved_baton = 1;
+}
+
+static void test_async_resolve_cancel(CuTest *tc)
+{
+    test_baton_t *tb = tc->testBaton;
+    serf_context_t *ctx;
+    apr_pool_t *ctx_pool;
+    apr_status_t status;
+    apr_uri_t url;
+    int resolved = 0;
+
+    status = apr_uri_parse(tb->pool, "http://localhost:8080/";, &url);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+    apr_pool_create(&ctx_pool, tb->pool);
+    CuAssertPtrNotNull(tc, ctx_pool);
+    ctx = serf_context_create(ctx_pool);
+    CuAssertPtrNotNull(tc, ctx);
+
+    status = serf_address_resolve_async(ctx, url,
+                                        async_resolve_cancel_callback,
+                                        &resolved, ctx_pool);
+
+    /* This would create and actual race in the test case: */
+    /* serf_context_prerun(ctx); */
+
+    apr_pool_destroy(ctx_pool);
+    CuAssertIntEquals(tc, APR_SUCCESS, status);
+    CuAssertIntEquals(tc, 0, resolved);
+}
+
 
 /*****************************************************************************/
 CuSuite *test_context(void)
@@ -1086,5 +1124,6 @@ CuSuite *test_context(void)
     SUITE_ADD_TEST(suite, test_max_keepalive_requests);
     SUITE_ADD_TEST(suite, test_outgoing_request_err);
     SUITE_ADD_TEST(suite, test_async_resolve);
+    SUITE_ADD_TEST(suite, test_async_resolve_cancel);
     return suite;
 }


Reply via email to