]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Improve locking performance in dispatch.c
authorEvan Hunt <each@isc.org>
Sat, 28 Apr 2012 21:52:28 +0000 (14:52 -0700)
committerEvan Hunt <each@isc.org>
Sat, 28 Apr 2012 21:52:28 +0000 (14:52 -0700)
3316. [tuning] Improved locking performance when recursing.
[RT #28836]

   - Use one lock per memory pool instead of associating
     them all with a single 'pool_lock' in the dispatch manager.
   - Reduce the critical sections for qid->lock in get_dispsocket(),
     deref_portentry() and dns_dispatch_addresponse2().
   - Added a memory pool for socket events in dns_dispatch_t.
   - Add an isc_socketevent_t member in the resquery_t object, and use
     it with isc_socket_sendto2() instead of using isc_socket_sendto()
   - Tuned the memory pools in dispatch.c for better performance
     under load

CHANGES
lib/dns/dispatch.c
lib/dns/resolver.c
lib/isc/include/isc/socket.h
lib/isc/socket_api.c
lib/isc/unix/socket.c

diff --git a/CHANGES b/CHANGES
index ecbb6b915308f2eb29b9db8c78c00d9be855df78..4d56520f368bf5592e9b3413fcc8c7ae12d2f49f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+3316.  [tuning]        Improved locking performance when recursing.
+                       [RT #28836]
+
 3315.  [tuning]        Use multiple dispatch objects for sending upstream
                        queries; this can improve performance on busy
                        multiprocessor systems by reducing lock contention.
index d2307b68f6b9e7e0911d0c686e8cab344b34b25d..d8e4a153dd4a980fe60ea6b649013b2b47183709 100644 (file)
@@ -32,6 +32,7 @@
 #include <isc/portset.h>
 #include <isc/print.h>
 #include <isc/random.h>
+#include <isc/socket.h>
 #include <isc/stats.h>
 #include <isc/string.h>
 #include <isc/task.h>
@@ -101,12 +102,16 @@ struct dns_dispatchmgr {
        unsigned int                    maxbuffers; /*%< max buffers */
 
        /* Locked internally. */
-       isc_mutex_t                     pool_lock;
-       isc_mempool_t                  *epool;  /*%< memory pool for events */
-       isc_mempool_t                  *rpool;  /*%< memory pool for replies */
+       isc_mutex_t                     depool_lock;
+       isc_mempool_t                  *depool; /*%< pool for dispatch events */
+       isc_mutex_t                     rpool_lock;
+       isc_mempool_t                  *rpool;  /*%< pool for replies */
+       isc_mutex_t                     dpool_lock;
        isc_mempool_t                  *dpool;  /*%< dispatch allocations */
-       isc_mempool_t                  *bpool;  /*%< memory pool for buffers */
-       isc_mempool_t                  *spool;  /*%< memory pool for dispsocs */
+       isc_mutex_t                     bpool_lock;
+       isc_mempool_t                  *bpool;  /*%< pool for buffers */
+       isc_mutex_t                     spool_lock;
+       isc_mempool_t                  *spool;  /*%< pool for dispsocks */
 
        /*%
         * Locked by qid->lock if qid exists; otherwise, can be used without
@@ -226,6 +231,9 @@ struct dns_dispatch {
        unsigned int            maxrequests;    /*%< max requests */
        isc_event_t            *ctlevent;
 
+       isc_mutex_t             sepool_lock;
+       isc_mempool_t          *sepool;         /*%< pool for socket events */
+
        /*% Locked by mgr->lock. */
        ISC_LINK(dns_dispatch_t) link;
 
@@ -301,8 +309,8 @@ static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t,
                             in_port_t);
 static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
 static void *allocate_udp_buffer(dns_dispatch_t *disp);
-static inline void free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
-static inline dns_dispatchevent_t *allocate_event(dns_dispatch_t *disp);
+static inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
+static inline dns_dispatchevent_t *allocate_devent(dns_dispatch_t *disp);
 static void do_cancel(dns_dispatch_t *disp);
 static dns_dispentry_t *linear_first(dns_qid_t *disp);
 static dns_dispentry_t *linear_next(dns_qid_t *disp,
@@ -723,6 +731,11 @@ destroy_disp(isc_task_t *task, isc_event_t *event) {
                     "shutting down; detaching from sock %p, task %p",
                     disp->socket, disp->task[0]); /* XXXX */
 
+       if (disp->sepool != NULL) {
+               isc_mempool_destroy(&disp->sepool);
+               isc_mutex_destroy(&disp->sepool_lock);
+       }
+
        if (disp->socket != NULL)
                isc_socket_detach(&disp->socket);
        while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) {
@@ -787,6 +800,7 @@ new_portentry(dns_dispatch_t *disp, in_port_t port) {
 static void
 deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) {
        dispportentry_t *portentry = *portentryp;
+       isc_boolean_t unlink = ISC_FALSE;
        dns_qid_t *qid;
 
        REQUIRE(disp->port_table != NULL);
@@ -795,7 +809,10 @@ deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) {
        qid = DNS_QID(disp);
        LOCK(&qid->lock);
        portentry->refs--;
-       if (portentry->refs == 0) {
+       unlink = ISC_TF(portentry->refs == 0);
+       UNLOCK(&qid->lock);
+
+       if (unlink) {
                ISC_LIST_UNLINK(disp->port_table[portentry->port %
                                                 DNS_DISPATCH_PORTTABLESIZE],
                                portentry, link);
@@ -803,7 +820,6 @@ deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) {
        }
 
        *portentryp = NULL;
-       UNLOCK(&qid->lock);
 }
 
 /*%
@@ -833,12 +849,12 @@ socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port,
 
 /*%
  * Make a new socket for a single dispatch with a random port number.
- * The caller must hold the disp->lock and qid->lock.
+ * The caller must hold the disp->lock
  */
 static isc_result_t
 get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
-              isc_socketmgr_t *sockmgr, dns_qid_t *qid,
-              dispsocket_t **dispsockp, in_port_t *portp)
+              isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp,
+              in_port_t *portp)
 {
        int i;
        isc_uint32_t r;
@@ -853,6 +869,7 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
        in_port_t *ports;
        unsigned int bindoptions;
        dispportentry_t *portentry = NULL;
+       dns_qid_t *qid;
 
        if (isc_sockaddr_pf(&disp->local) == AF_INET) {
                nports = disp->mgr->nv4ports;
@@ -893,16 +910,23 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
         * very likely to fail in bind(2) or connect(2).
         */
        localaddr = disp->local;
+       qid = DNS_QID(disp);
+
        for (i = 0; i < 64; i++) {
                port = ports[dispatch_uniformrandom(DISP_ARC4CTX(disp),
                                                        nports)];
                isc_sockaddr_setport(&localaddr, port);
 
+               LOCK(&qid->lock);
                bucket = dns_hash(qid, dest, 0, port);
-               if (socket_search(qid, dest, port, bucket) != NULL)
+               if (socket_search(qid, dest, port, bucket) != NULL) {
+                       UNLOCK(&qid->lock);
                        continue;
+               }
+               UNLOCK(&qid->lock);
                bindoptions = 0;
                portentry = port_search(disp, port);
+
                if (portentry != NULL)
                        bindoptions |= ISC_SOCKET_REUSEADDRESS;
                result = open_socket(sockmgr, &localaddr, bindoptions, &sock,
@@ -932,7 +956,9 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
                dispsock->host = *dest;
                dispsock->portentry = portentry;
                dispsock->bucket = bucket;
+               LOCK(&qid->lock);
                ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink);
+               UNLOCK(&qid->lock);
                *dispsockp = dispsock;
                *portp = port;
        } else {
@@ -1067,6 +1093,7 @@ entry_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
 
 static void
 free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
+       isc_mempool_t *bpool;
        INSIST(buf != NULL && len != 0);
 
 
@@ -1081,8 +1108,9 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
                INSIST(disp->mgr->buffers > 0);
                INSIST(len == disp->mgr->buffersize);
                disp->mgr->buffers--;
-               isc_mempool_put(disp->mgr->bpool, buf);
+               bpool = disp->mgr->bpool;
                UNLOCK(&disp->mgr->buffer_lock);
+               isc_mempool_put(bpool, buf);
                break;
        default:
                INSIST(0);
@@ -1092,20 +1120,60 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
 
 static void *
 allocate_udp_buffer(dns_dispatch_t *disp) {
+       isc_mempool_t *bpool;
        void *temp;
 
        LOCK(&disp->mgr->buffer_lock);
-       temp = isc_mempool_get(disp->mgr->bpool);
-
-       if (temp != NULL)
-               disp->mgr->buffers++;
+       bpool = disp->mgr->bpool;
+       disp->mgr->buffers++;
        UNLOCK(&disp->mgr->buffer_lock);
 
+       temp = isc_mempool_get(bpool);
+
+       if (temp == NULL) {
+               LOCK(&disp->mgr->buffer_lock);
+               disp->mgr->buffers--;
+               UNLOCK(&disp->mgr->buffer_lock);
+       }
+
        return (temp);
 }
 
 static inline void
-free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
+free_sevent(isc_event_t *ev) {
+       isc_mempool_t *pool = ev->ev_destroy_arg;
+       isc_socketevent_t *sev = (isc_socketevent_t *) ev;
+       isc_mempool_put(pool, sev);
+}
+
+static inline isc_socketevent_t *
+allocate_sevent(dns_dispatch_t *disp, isc_socket_t *socket,
+               isc_eventtype_t type, isc_taskaction_t action, const void *arg)
+{
+       isc_socketevent_t *ev;
+       void *deconst_arg;
+
+       ev = isc_mempool_get(disp->sepool);
+       if (ev == NULL)
+               return (NULL);
+       DE_CONST(arg, deconst_arg);
+       ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type,
+                      action, deconst_arg, socket,
+                      free_sevent, disp->sepool);
+       ev->result = ISC_R_UNSET;
+       ISC_LINK_INIT(ev, ev_link);
+       ISC_LIST_INIT(ev->bufferlist);
+       ev->region.base = NULL;
+       ev->n = 0;
+       ev->offset = 0;
+       ev->attributes = 0;
+
+       return (ev);
+}
+
+
+static inline void
+free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
        if (disp->failsafe_ev == ev) {
                INSIST(disp->shutdown_out == 1);
                disp->shutdown_out = 0;
@@ -1113,14 +1181,14 @@ free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
                return;
        }
 
-       isc_mempool_put(disp->mgr->epool, ev);
+       isc_mempool_put(disp->mgr->depool, ev);
 }
 
 static inline dns_dispatchevent_t *
-allocate_event(dns_dispatch_t *disp) {
+allocate_devent(dns_dispatch_t *disp) {
        dns_dispatchevent_t *ev;
 
-       ev = isc_mempool_get(disp->mgr->epool);
+       ev = isc_mempool_get(disp->mgr->depool);
        if (ev == NULL)
                return (NULL);
        ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0,
@@ -1385,7 +1453,7 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) {
 
   sendresponse:
        queue_response = resp->item_out;
-       rev = allocate_event(resp->disp);
+       rev = allocate_devent(resp->disp);
        if (rev == NULL) {
                free_buffer(disp, ev->region.base, ev->region.length);
                goto unlock;
@@ -1583,7 +1651,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
        if (resp == NULL)
                goto unlock;
        queue_response = resp->item_out;
-       rev = allocate_event(disp);
+       rev = allocate_devent(disp);
        if (rev == NULL)
                goto unlock;
 
@@ -1664,16 +1732,33 @@ startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) {
                if (region.base == NULL)
                        return (ISC_R_NOMEMORY);
                if (dispsock != NULL) {
-                       res = isc_socket_recv(socket, &region, 1,
-                                             dispsock->task, udp_exrecv,
-                                             dispsock);
+                       isc_task_t *dt = dispsock->task;
+                       isc_socketevent_t *sev =
+                               allocate_sevent(disp, socket,
+                                               ISC_SOCKEVENT_RECVDONE,
+                                               udp_exrecv, dispsock);
+                       if (sev == NULL) {
+                               free_buffer(disp, region.base, region.length);
+                               return (ISC_R_NOMEMORY);
+                       }
+
+                       res = isc_socket_recv2(socket, &region, 1, dt, sev, 0);
                        if (res != ISC_R_SUCCESS) {
                                free_buffer(disp, region.base, region.length);
                                return (res);
                        }
                } else {
-                       res = isc_socket_recv(socket, &region, 1,
-                                             disp->task[0], udp_shrecv, disp);
+                       isc_task_t *dt = disp->task[0];
+                       isc_socketevent_t *sev =
+                               allocate_sevent(disp, socket,
+                                               ISC_SOCKEVENT_RECVDONE,
+                                               udp_shrecv, disp);
+                       if (sev == NULL) {
+                               free_buffer(disp, region.base, region.length);
+                               return (ISC_R_NOMEMORY);
+                       }
+
+                       res = isc_socket_recv2(socket, &region, 1, dt, sev, 0);
                        if (res != ISC_R_SUCCESS) {
                                free_buffer(disp, region.base, region.length);
                                disp->shutdown_why = res;
@@ -1713,16 +1798,16 @@ static isc_boolean_t
 destroy_mgr_ok(dns_dispatchmgr_t *mgr) {
        mgr_log(mgr, LVL(90),
                "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, "
-               "epool=%d, rpool=%d, dpool=%d",
+               "depool=%d, rpool=%d, dpool=%d",
                MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list),
-               isc_mempool_getallocated(mgr->epool),
+               isc_mempool_getallocated(mgr->depool),
                isc_mempool_getallocated(mgr->rpool),
                isc_mempool_getallocated(mgr->dpool));
        if (!MGR_IS_SHUTTINGDOWN(mgr))
                return (ISC_FALSE);
        if (!ISC_LIST_EMPTY(mgr->list))
                return (ISC_FALSE);
-       if (isc_mempool_getallocated(mgr->epool) != 0)
+       if (isc_mempool_getallocated(mgr->depool) != 0)
                return (ISC_FALSE);
        if (isc_mempool_getallocated(mgr->rpool) != 0)
                return (ISC_FALSE);
@@ -1752,7 +1837,7 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) {
 
        DESTROYLOCK(&mgr->arc4_lock);
 
-       isc_mempool_destroy(&mgr->epool);
+       isc_mempool_destroy(&mgr->depool);
        isc_mempool_destroy(&mgr->rpool);
        isc_mempool_destroy(&mgr->dpool);
        if (mgr->bpool != NULL)
@@ -1760,7 +1845,11 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) {
        if (mgr->spool != NULL)
                isc_mempool_destroy(&mgr->spool);
 
-       DESTROYLOCK(&mgr->pool_lock);
+       DESTROYLOCK(&mgr->spool_lock);
+       DESTROYLOCK(&mgr->bpool_lock);
+       DESTROYLOCK(&mgr->dpool_lock);
+       DESTROYLOCK(&mgr->rpool_lock);
+       DESTROYLOCK(&mgr->depool_lock);
 
 #ifdef BIND9
        if (mgr->entropy != NULL)
@@ -1900,22 +1989,38 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
        if (result != ISC_R_SUCCESS)
                goto kill_arc4_lock;
 
-       result = isc_mutex_init(&mgr->pool_lock);
+       result = isc_mutex_init(&mgr->depool_lock);
        if (result != ISC_R_SUCCESS)
                goto kill_buffer_lock;
 
-       mgr->epool = NULL;
+       result = isc_mutex_init(&mgr->rpool_lock);
+       if (result != ISC_R_SUCCESS)
+               goto kill_depool_lock;
+
+       result = isc_mutex_init(&mgr->dpool_lock);
+       if (result != ISC_R_SUCCESS)
+               goto kill_rpool_lock;
+
+       result = isc_mutex_init(&mgr->bpool_lock);
+       if (result != ISC_R_SUCCESS)
+               goto kill_dpool_lock;
+
+       result = isc_mutex_init(&mgr->spool_lock);
+       if (result != ISC_R_SUCCESS)
+               goto kill_bpool_lock;
+
+       mgr->depool = NULL;
        if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t),
-                              &mgr->epool) != ISC_R_SUCCESS) {
+                              &mgr->depool) != ISC_R_SUCCESS) {
                result = ISC_R_NOMEMORY;
-               goto kill_pool_lock;
+               goto kill_spool_lock;
        }
 
        mgr->rpool = NULL;
        if (isc_mempool_create(mgr->mctx, sizeof(dns_dispentry_t),
                               &mgr->rpool) != ISC_R_SUCCESS) {
                result = ISC_R_NOMEMORY;
-               goto kill_epool;
+               goto kill_depool;
        }
 
        mgr->dpool = NULL;
@@ -1925,17 +2030,23 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
                goto kill_rpool;
        }
 
-       isc_mempool_setname(mgr->epool, "dispmgr_epool");
-       isc_mempool_setfreemax(mgr->epool, 1024);
-       isc_mempool_associatelock(mgr->epool, &mgr->pool_lock);
+       isc_mempool_setname(mgr->depool, "dispmgr_depool");
+       isc_mempool_setmaxalloc(mgr->depool, 32768);
+       isc_mempool_setfreemax(mgr->depool, 32768);
+       isc_mempool_associatelock(mgr->depool, &mgr->depool_lock);
+       isc_mempool_setfillcount(mgr->depool, 32);
 
        isc_mempool_setname(mgr->rpool, "dispmgr_rpool");
-       isc_mempool_setfreemax(mgr->rpool, 1024);
-       isc_mempool_associatelock(mgr->rpool, &mgr->pool_lock);
+       isc_mempool_setmaxalloc(mgr->rpool, 32768);
+       isc_mempool_setfreemax(mgr->rpool, 32768);
+       isc_mempool_associatelock(mgr->rpool, &mgr->rpool_lock);
+       isc_mempool_setfillcount(mgr->rpool, 32);
 
        isc_mempool_setname(mgr->dpool, "dispmgr_dpool");
-       isc_mempool_setfreemax(mgr->dpool, 1024);
-       isc_mempool_associatelock(mgr->dpool, &mgr->pool_lock);
+       isc_mempool_setmaxalloc(mgr->dpool, 32768);
+       isc_mempool_setfreemax(mgr->dpool, 32768);
+       isc_mempool_associatelock(mgr->dpool, &mgr->dpool_lock);
+       isc_mempool_setfillcount(mgr->dpool, 32);
 
        mgr->buffers = 0;
        mgr->buffersize = 0;
@@ -1984,10 +2095,18 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
        isc_mempool_destroy(&mgr->dpool);
  kill_rpool:
        isc_mempool_destroy(&mgr->rpool);
- kill_epool:
-       isc_mempool_destroy(&mgr->epool);
- kill_pool_lock:
-       DESTROYLOCK(&mgr->pool_lock);
+ kill_depool:
+       isc_mempool_destroy(&mgr->depool);
+ kill_spool_lock:
+       DESTROYLOCK(&mgr->spool_lock);
+ kill_bpool_lock:
+       DESTROYLOCK(&mgr->bpool_lock);
+ kill_dpool_lock:
+       DESTROYLOCK(&mgr->dpool_lock);
+ kill_rpool_lock:
+       DESTROYLOCK(&mgr->rpool_lock);
+ kill_depool_lock:
+       DESTROYLOCK(&mgr->depool_lock);
  kill_buffer_lock:
        DESTROYLOCK(&mgr->buffer_lock);
  kill_arc4_lock:
@@ -2141,6 +2260,7 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
                 */
                if (maxbuffers > mgr->maxbuffers) {
                        isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
+                       isc_mempool_setfreemax(mgr->bpool, maxbuffers);
                        mgr->maxbuffers = maxbuffers;
                }
        } else {
@@ -2151,12 +2271,18 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
                }
                isc_mempool_setname(mgr->bpool, "dispmgr_bpool");
                isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
-               isc_mempool_associatelock(mgr->bpool, &mgr->pool_lock);
+               isc_mempool_setfreemax(mgr->bpool, maxbuffers);
+               isc_mempool_associatelock(mgr->bpool, &mgr->bpool_lock);
+               isc_mempool_setfillcount(mgr->bpool, 32);
        }
 
        /* Create or adjust socket pool */
        if (mgr->spool != NULL) {
-               isc_mempool_setmaxalloc(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2);
+               if (maxrequests < DNS_DISPATCH_POOLSOCKS * 2)
+                 isc_mempool_setmaxalloc(mgr->spool,
+                                         DNS_DISPATCH_POOLSOCKS * 2);
+                 isc_mempool_setfreemax(mgr->spool,
+                                        DNS_DISPATCH_POOLSOCKS * 2);
                UNLOCK(&mgr->buffer_lock);
                return (ISC_R_SUCCESS);
        }
@@ -2168,7 +2294,9 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
        }
        isc_mempool_setname(mgr->spool, "dispmgr_spool");
        isc_mempool_setmaxalloc(mgr->spool, maxrequests);
-       isc_mempool_associatelock(mgr->spool, &mgr->pool_lock);
+       isc_mempool_setfreemax(mgr->spool, maxrequests);
+       isc_mempool_associatelock(mgr->spool, &mgr->spool_lock);
+       isc_mempool_setfillcount(mgr->spool, 32);
 
        result = qid_allocate(mgr, buckets, increment, &mgr->qid, ISC_TRUE);
        if (result != ISC_R_SUCCESS)
@@ -2494,7 +2622,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
        if (result != ISC_R_SUCCESS)
                goto deallocate;
 
-       disp->failsafe_ev = allocate_event(disp);
+       disp->failsafe_ev = allocate_devent(disp);
        if (disp->failsafe_ev == NULL) {
                result = ISC_R_NOMEMORY;
                goto kill_lock;
@@ -2545,7 +2673,7 @@ dispatch_free(dns_dispatch_t **dispp)
        INSIST(ISC_LIST_EMPTY(disp->activesockets));
        INSIST(ISC_LIST_EMPTY(disp->inactivesockets));
 
-       isc_mempool_put(mgr->epool, disp->failsafe_ev);
+       isc_mempool_put(mgr->depool, disp->failsafe_ev);
        disp->failsafe_ev = NULL;
 
        if (disp->qid != NULL)
@@ -2609,6 +2737,8 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
        disp->socket = NULL;
        isc_socket_attach(sock, &disp->socket);
 
+       disp->sepool = NULL;
+
        disp->ntasks = 1;
        disp->task[0] = NULL;
        result = isc_task_create(taskmgr, 0, &disp->task[0]);
@@ -2973,6 +3103,24 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
                goto kill_task;
        }
 
+       disp->sepool = NULL;
+       if (isc_mempool_create(mgr->mctx, sizeof(isc_socketevent_t),
+                              &disp->sepool) != ISC_R_SUCCESS)
+       {
+               result = ISC_R_NOMEMORY;
+               goto kill_ctlevent;
+       }
+
+       result = isc_mutex_init(&disp->sepool_lock);
+       if (result != ISC_R_SUCCESS)
+               goto kill_sepool;
+
+       isc_mempool_setname(disp->sepool, "disp_sepool");
+       isc_mempool_setmaxalloc(disp->sepool, 32768);
+       isc_mempool_setfreemax(disp->sepool, 32768);
+       isc_mempool_associatelock(disp->sepool, &disp->sepool_lock);
+       isc_mempool_setfillcount(disp->sepool, 16);
+
        attributes &= ~DNS_DISPATCHATTR_TCP;
        attributes |= DNS_DISPATCHATTR_UDP;
        disp->attributes = attributes;
@@ -2994,6 +3142,10 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
        /*
         * Error returns.
         */
+ kill_sepool:
+       isc_mempool_destroy(&disp->sepool);
+ kill_ctlevent:
+       isc_event_free(&disp->ctlevent);
  kill_task:
        for (i = 0; i < disp->ntasks; i++)
                isc_task_detach(&disp->task[i]);
@@ -3110,7 +3262,7 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
                oldestsocket = ISC_LIST_HEAD(disp->activesockets);
                oldestresp = oldestsocket->resp;
                if (oldestresp != NULL && !oldestresp->item_out) {
-                       rev = allocate_event(oldestresp->disp);
+                       rev = allocate_devent(oldestresp->disp);
                        if (rev != NULL) {
                                rev->buffer.base = NULL;
                                rev->result = ISC_R_CANCELED;
@@ -3137,16 +3289,14 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
        }
 
        qid = DNS_QID(disp);
-       LOCK(&qid->lock);
 
        if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
                /*
                 * Get a separate UDP socket with a random port number.
                 */
-               result = get_dispsocket(disp, dest, sockmgr, qid, &dispsocket,
+               result = get_dispsocket(disp, dest, sockmgr, &dispsocket,
                                        &localport);
                if (result != ISC_R_SUCCESS) {
-                       UNLOCK(&qid->lock);
                        UNLOCK(&disp->lock);
                        inc_stats(disp->mgr, dns_resstatscounter_dispsockfail);
                        return (result);
@@ -3158,6 +3308,7 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
        /*
         * Try somewhat hard to find an unique ID.
         */
+       LOCK(&qid->lock);
        id = (dns_messageid_t)dispatch_random(DISP_ARC4CTX(disp));
        bucket = dns_hash(qid, dest, id, localport);
        ok = ISC_FALSE;
@@ -3170,16 +3321,15 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
                id &= 0x0000ffff;
                bucket = dns_hash(qid, dest, id, localport);
        }
+       UNLOCK(&qid->lock);
 
        if (!ok) {
-               UNLOCK(&qid->lock);
                UNLOCK(&disp->lock);
                return (ISC_R_NOMORE);
        }
 
        res = isc_mempool_get(disp->mgr->rpool);
        if (res == NULL) {
-               UNLOCK(&qid->lock);
                UNLOCK(&disp->lock);
                if (dispsocket != NULL)
                        destroy_dispsocket(disp, &dispsocket);
@@ -3204,6 +3354,8 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
        ISC_LIST_INIT(res->items);
        ISC_LINK_INIT(res, link);
        res->magic = RESPONSE_MAGIC;
+
+       LOCK(&qid->lock);
        ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
        UNLOCK(&qid->lock);
 
@@ -3351,7 +3503,7 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp,
                res->item_out = ISC_FALSE;
                if (ev->buffer.base != NULL)
                        free_buffer(disp, ev->buffer.base, ev->buffer.length);
-               free_event(disp, ev);
+               free_devent(disp, ev);
        }
 
        request_log(disp, res, LVL(90), "detaching from task %p", res->task);
@@ -3371,7 +3523,7 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp,
                ISC_LIST_UNLINK(res->items, ev, ev_link);
                if (ev->buffer.base != NULL)
                        free_buffer(disp, ev->buffer.base, ev->buffer.length);
-               free_event(disp, ev);
+               free_devent(disp, ev);
                ev = ISC_LIST_HEAD(res->items);
        }
        res->magic = 0;
index 74d82ae1076a80dc8edf8964b295b40d93b735d1..b021821d6c247cfc653fff20b56ed615c1b6872e 100644 (file)
@@ -25,8 +25,9 @@
 #include <isc/print.h>
 #include <isc/string.h>
 #include <isc/random.h>
-#include <isc/task.h>
+#include <isc/socket.h>
 #include <isc/stats.h>
+#include <isc/task.h>
 #include <isc/timer.h>
 #include <isc/util.h>
 
@@ -143,6 +144,7 @@ typedef struct query {
        isc_buffer_t                    buffer;
        isc_buffer_t                    *tsig;
        dns_tsigkey_t                   *tsigkey;
+       isc_socketevent_t               sendevent;
        unsigned int                    options;
        unsigned int                    attributes;
        unsigned int                    sends;
@@ -1194,7 +1196,8 @@ process_sendevent(resquery_t *query, isc_event_t *event) {
                }
        }
 
-       isc_event_free(&event);
+       if (event->ev_type == ISC_SOCKEVENT_CONNECT)
+               isc_event_free(&event);
 
        if (retry) {
                /*
@@ -1990,8 +1993,11 @@ resquery_send(resquery_t *query) {
         * XXXRTH  Make sure we don't send to ourselves!  We should probably
         *              prune out these addresses when we get them from the ADB.
         */
-       result = isc_socket_sendto(socket, &r, task, resquery_senddone,
-                                  query, address, NULL);
+       ISC_EVENT_INIT(&query->sendevent, sizeof(query->sendevent), 0, NULL,
+                      ISC_SOCKEVENT_SENDDONE, resquery_senddone, query,
+                      NULL, NULL, NULL);
+       result = isc_socket_sendto2(socket, &r, task, address, NULL,
+                                   &query->sendevent, 0);
        if (result != ISC_R_SUCCESS) {
                if (connecting) {
                        /*
index 38f6f78025df1e80b9f0697aff97dd708ff96b3b..d59ade659b59d47a4cf3b35a34c9ea04345f5c86 100644 (file)
@@ -283,12 +283,20 @@ typedef struct isc_socketmethods {
                                  isc_task_t *task, isc_taskaction_t action,
                                  const void *arg, isc_sockaddr_t *address,
                                  struct in6_pktinfo *pktinfo);
+       isc_result_t    (*sendto2)(isc_socket_t *sock, isc_region_t *region,
+                                  isc_task_t *task, isc_sockaddr_t *address,
+                                  struct in6_pktinfo *pktinfo,
+                                  isc_socketevent_t *event,
+                                  unsigned int flags);
        isc_result_t    (*connect)(isc_socket_t *sock, isc_sockaddr_t *addr,
                                   isc_task_t *task, isc_taskaction_t action,
                                   const void *arg);
        isc_result_t    (*recv)(isc_socket_t *sock, isc_region_t *region,
                                unsigned int minimum, isc_task_t *task,
                                isc_taskaction_t action, const void *arg);
+       isc_result_t    (*recv2)(isc_socket_t *sock, isc_region_t *region,
+                                unsigned int minimum, isc_task_t *task,
+                                isc_socketevent_t *event, unsigned int flags);
        void            (*cancel)(isc_socket_t *sock, isc_task_t *task,
                                  unsigned int how);
        isc_result_t    (*getsockname)(isc_socket_t *sock,
index 3394ce059b50d2fe0be9c6c93df734013503d3b0..1fba3e0ac19ace1a918b5a20cba42bd8726c4c71 100644 (file)
@@ -140,6 +140,18 @@ isc_socket_sendto(isc_socket_t *sock, isc_region_t *region, isc_task_t *task,
                                      pktinfo));
 }
 
+isc_result_t
+isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
+                  isc_task_t *task, isc_sockaddr_t *address,
+                  struct in6_pktinfo *pktinfo, isc_socketevent_t *event,
+                  unsigned int flags)
+{
+       REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+       return (sock->methods->sendto2(sock, region, task, address,
+                                      pktinfo, event, flags));
+}
+
 isc_result_t
 isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, isc_task_t *task,
                   isc_taskaction_t action, const void *arg)
@@ -158,6 +170,17 @@ isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
        return (sock->methods->recv(sock, region, minimum, task, action, arg));
 }
 
+isc_result_t
+isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
+                unsigned int minimum, isc_task_t *task,
+                isc_socketevent_t *event, unsigned int flags)
+{
+       REQUIRE(ISCAPI_SOCKET_VALID(sock));
+
+       return (sock->methods->recv2(sock, region, minimum, task,
+                                    event, flags));
+}
+
 void
 isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
        REQUIRE(ISCAPI_SOCKET_VALID(sock));
index 5fed888a11ae2752aae4052bcb5d5c23c41ba5a4..057aa1e81d5c4ee6ec9e3669ddf1d3c02a19d040 100644 (file)
@@ -572,8 +572,10 @@ static struct {
                isc__socket_detach,
                isc__socket_bind,
                isc__socket_sendto,
+               isc__socket_sendto2,
                isc__socket_connect,
                isc__socket_recv,
+               isc__socket_recv2,
                isc__socket_cancel,
                isc__socket_getsockname,
                isc__socket_gettype,