]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Have the dns_client hold a .references until all external references are removed
authorOndřej Surý <ondrej@sury.org>
Tue, 6 Aug 2019 15:35:20 +0000 (17:35 +0200)
committerOndřej Surý <ondrej@sury.org>
Wed, 7 Aug 2019 09:35:06 +0000 (11:35 +0200)
so that cleanup can all be done in dns_client_destroy().

lib/dns/client.c

index 6cef2a5ae7cad90bffbfee90397f163386a7d111..5140956f17045416f8000fc306394f53060d1f4c 100644 (file)
@@ -19,6 +19,7 @@
 #include <isc/mem.h>
 #include <isc/mutex.h>
 #include <isc/portset.h>
+#include <isc/refcount.h>
 #include <isc/safe.h>
 #include <isc/sockaddr.h>
 #include <isc/socket.h>
@@ -94,8 +95,9 @@ struct dns_client {
        unsigned int                    find_timeout;
        unsigned int                    find_udpretries;
 
+       isc_refcount_t                  references;
+
        /* Locked */
-       unsigned int                    references;
        dns_viewlist_t                  viewlist;
        ISC_LIST(struct resctx)         resctxs;
        ISC_LIST(struct reqctx)         reqctxs;
@@ -508,8 +510,7 @@ dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
 
        result = isc_mutex_init(&client->lock);
        if (result != ISC_R_SUCCESS) {
-               isc_mem_put(mctx, client, sizeof(*client));
-               return (result);
+               goto cleanup_client;
        }
 
        client->actx = actx;
@@ -519,12 +520,14 @@ dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
 
        client->task = NULL;
        result = isc_task_create(client->taskmgr, 0, &client->task);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup;
+       if (result != ISC_R_SUCCESS) {
+               goto cleanup_lock;
+       }
 
        result = dns_dispatchmgr_create(mctx, NULL, &dispatchmgr);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup;
+       if (result != ISC_R_SUCCESS) {
+               goto cleanup_task;
+       }
        client->dispatchmgr = dispatchmgr;
        (void)setsourceports(mctx, dispatchmgr);
 
@@ -537,8 +540,9 @@ dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
                result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
                                        taskmgr, true,
                                        &dispatchv4, localaddr4);
-               if (result == ISC_R_SUCCESS)
+               if (result == ISC_R_SUCCESS) {
                        client->dispatchv4 = dispatchv4;
+               }
        }
 
        client->dispatchv6 = NULL;
@@ -546,22 +550,30 @@ dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
                result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
                                        taskmgr, true,
                                        &dispatchv6, localaddr6);
-               if (result == ISC_R_SUCCESS)
+               if (result == ISC_R_SUCCESS) {
                        client->dispatchv6 = dispatchv6;
+               }
        }
 
        /* We need at least one of the dispatchers */
        if (dispatchv4 == NULL && dispatchv6 == NULL) {
                INSIST(result != ISC_R_SUCCESS);
-               goto cleanup;
+               goto cleanup_dispatchmgr;
+       }
+
+       result = isc_refcount_init(&client->references, 1);
+       if (result != ISC_R_SUCCESS) {
+               goto cleanup_dispatches;
        }
 
        /* Create the default view for class IN */
        result = createview(mctx, dns_rdataclass_in, options, taskmgr,
                            RESOLVER_NTASKS, socketmgr, timermgr,
                            dispatchmgr, dispatchv4, dispatchv6, &view);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup;
+       if (result != ISC_R_SUCCESS) {
+               goto cleanup_references;
+       }
+
        ISC_LIST_INIT(client->viewlist);
        ISC_LIST_APPEND(client->viewlist, view, link);
 
@@ -581,32 +593,38 @@ dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
        client->find_udpretries = DEF_FIND_UDPRETRIES;
        client->attributes = 0;
 
-       client->references = 1;
        client->magic = DNS_CLIENT_MAGIC;
 
        *clientp = client;
 
        return (ISC_R_SUCCESS);
 
- cleanup:
+ cleanup_references:
+       isc_refcount_decrement(&client->references, NULL);
+       isc_refcount_destroy(&client->references);
+ cleanup_dispatches:
        if (dispatchv4 != NULL)
                dns_dispatch_detach(&dispatchv4);
        if (dispatchv6 != NULL)
                dns_dispatch_detach(&dispatchv6);
-       if (dispatchmgr != NULL)
-               dns_dispatchmgr_destroy(&dispatchmgr);
-       if (client->task != NULL)
-               isc_task_detach(&client->task);
+ cleanup_dispatchmgr:
+       dns_dispatchmgr_destroy(&dispatchmgr);
+ cleanup_task:
+       isc_task_detach(&client->task);
+ cleanup_lock:
+       DESTROYLOCK(&client->lock);
+ cleanup_client:
        isc_mem_put(mctx, client, sizeof(*client));
 
        return (result);
 }
 
 static void
-destroyclient(dns_client_t **clientp) {
-       dns_client_t *client = *clientp;
+destroyclient(dns_client_t *client) {
        dns_view_t *view;
 
+       isc_refcount_destroy(&client->references);
+
        while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
                ISC_LIST_UNLINK(client->viewlist, view, link);
                dns_view_detach(&view);
@@ -638,32 +656,22 @@ destroyclient(dns_client_t **clientp) {
        client->magic = 0;
 
        isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
-
-       *clientp = NULL;
 }
 
 void
 dns_client_destroy(dns_client_t **clientp) {
        dns_client_t *client;
-       bool destroyok = false;
+       uint32_t references;
 
        REQUIRE(clientp != NULL);
        client = *clientp;
+       *clientp = NULL;
        REQUIRE(DNS_CLIENT_VALID(client));
 
-       LOCK(&client->lock);
-       client->references--;
-       if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
-           ISC_LIST_EMPTY(client->reqctxs) &&
-           ISC_LIST_EMPTY(client->updatectxs)) {
-               destroyok = true;
+       isc_refcount_decrement(&client->references, &references);
+       if (references == 0U) {
+               destroyclient(client);
        }
-       UNLOCK(&client->lock);
-
-       if (destroyok)
-               destroyclient(&client);
-
-       *clientp = NULL;
 }
 
 isc_result_t
@@ -1459,6 +1467,7 @@ dns_client_startresolve(dns_client_t *client, dns_name_t *name,
        rctx->event = event;
 
        rctx->magic = RCTX_MAGIC;
+       isc_refcount_increment(&client->references, NULL);
 
        LOCK(&client->lock);
        ISC_LIST_APPEND(client->resctxs, rctx, link);
@@ -1529,10 +1538,10 @@ dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
        resctx_t *rctx;
        isc_mem_t *mctx;
        dns_client_t *client;
-       bool need_destroyclient = false;
 
        REQUIRE(transp != NULL);
        rctx = (resctx_t *)*transp;
+       *transp = NULL;
        REQUIRE(RCTX_VALID(rctx));
        REQUIRE(rctx->fetch == NULL);
        REQUIRE(rctx->event == NULL);
@@ -1554,11 +1563,6 @@ dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
        INSIST(ISC_LINK_LINKED(rctx, link));
        ISC_LIST_UNLINK(client->resctxs, rctx, link);
 
-       if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
-           ISC_LIST_EMPTY(client->reqctxs) &&
-           ISC_LIST_EMPTY(client->updatectxs))
-               need_destroyclient = true;
-
        UNLOCK(&client->lock);
 
        INSIST(ISC_LIST_EMPTY(rctx->namelist));
@@ -1568,10 +1572,8 @@ dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
 
        isc_mem_put(mctx, rctx, sizeof(*rctx));
 
-       if (need_destroyclient)
-               destroyclient(&client);
+       dns_client_destroy(&client);
 
-       *transp = NULL;
 }
 
 isc_result_t
@@ -1845,6 +1847,7 @@ dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
 
        LOCK(&client->lock);
        ISC_LIST_APPEND(client->reqctxs, ctx, link);
+       isc_refcount_increment(&client->references, NULL);
        UNLOCK(&client->lock);
 
        ctx->request = NULL;
@@ -1859,6 +1862,8 @@ dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
                return (ISC_R_SUCCESS);
        }
 
+       isc_refcount_decrement(&client->references, NULL);
+
  cleanup:
        if (ctx != NULL) {
                LOCK(&client->lock);
@@ -1899,10 +1904,10 @@ dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
        reqctx_t *ctx;
        isc_mem_t *mctx;
        dns_client_t *client;
-       bool need_destroyclient = false;
 
        REQUIRE(transp != NULL);
        ctx = (reqctx_t *)*transp;
+       *transp = NULL;
        REQUIRE(REQCTX_VALID(ctx));
        client = ctx->client;
        REQUIRE(DNS_CLIENT_VALID(client));
@@ -1917,12 +1922,6 @@ dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
        INSIST(ISC_LINK_LINKED(ctx, link));
        ISC_LIST_UNLINK(client->reqctxs, ctx, link);
 
-       if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
-           ISC_LIST_EMPTY(client->reqctxs) &&
-           ISC_LIST_EMPTY(client->updatectxs)) {
-               need_destroyclient = true;
-       }
-
        UNLOCK(&client->lock);
 
        DESTROYLOCK(&ctx->lock);
@@ -1930,10 +1929,7 @@ dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
 
        isc_mem_put(mctx, ctx, sizeof(*ctx));
 
-       if (need_destroyclient)
-               destroyclient(&client);
-
-       *transp = NULL;
+       dns_client_destroy(&client);
 }
 
 /*%
@@ -3023,6 +3019,7 @@ dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
 
        LOCK(&client->lock);
        ISC_LIST_APPEND(client->updatectxs, uctx, link);
+       isc_refcount_increment(&client->references, NULL);
        UNLOCK(&client->lock);
 
        *transp = (dns_clientupdatetrans_t *)uctx;
@@ -3041,6 +3038,8 @@ dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
        }
        if (result == ISC_R_SUCCESS)
                return (result);
+
+       isc_refcount_decrement(&client->references, NULL);
        *transp = NULL;
 
  fail:
@@ -3098,11 +3097,11 @@ dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
        updatectx_t *uctx;
        isc_mem_t *mctx;
        dns_client_t *client;
-       bool need_destroyclient = false;
        isc_sockaddr_t *sa;
 
        REQUIRE(transp != NULL);
        uctx = (updatectx_t *)*transp;
+       *transp = NULL;
        REQUIRE(UCTX_VALID(uctx));
        client = uctx->client;
        REQUIRE(DNS_CLIENT_VALID(client));
@@ -3123,11 +3122,6 @@ dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
        INSIST(ISC_LINK_LINKED(uctx, link));
        ISC_LIST_UNLINK(client->updatectxs, uctx, link);
 
-       if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
-           ISC_LIST_EMPTY(client->reqctxs) &&
-           ISC_LIST_EMPTY(client->updatectxs))
-               need_destroyclient = true;
-
        UNLOCK(&client->lock);
 
        DESTROYLOCK(&uctx->lock);
@@ -3135,10 +3129,7 @@ dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
 
        isc_mem_put(mctx, uctx, sizeof(*uctx));
 
-       if (need_destroyclient)
-               destroyclient(&client);
-
-       *transp = NULL;
+       dns_client_destroy(&client);
 }
 
 isc_mem_t *