From: Evan Hunt Date: Sat, 28 Apr 2012 21:52:28 +0000 (-0700) Subject: Improve locking performance in dispatch.c X-Git-Tag: v9.10.0a1~1180^2~84 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=54489ba1672458382e8dfb5490fcfc7230f8ea85;p=thirdparty%2Fbind9.git Improve locking performance in dispatch.c 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 --- diff --git a/CHANGES b/CHANGES index ecbb6b91530..4d56520f368 100644 --- 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. diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index d2307b68f6b..d8e4a153dd4 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -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, ®ion, 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, ®ion, 1, dt, sev, 0); if (res != ISC_R_SUCCESS) { free_buffer(disp, region.base, region.length); return (res); } } else { - res = isc_socket_recv(socket, ®ion, 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, ®ion, 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; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 74d82ae1076..b021821d6c2 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -25,8 +25,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -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) { /* diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index 38f6f78025d..d59ade659b5 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -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, diff --git a/lib/isc/socket_api.c b/lib/isc/socket_api.c index 3394ce059b5..1fba3e0ac19 100644 --- a/lib/isc/socket_api.c +++ b/lib/isc/socket_api.c @@ -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)); diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 5fed888a11a..057aa1e81d5 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -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,