From 54a64ec428cb9f783d62a044cbec3a72724a937c Mon Sep 17 00:00:00 2001 From: Michael Graff Date: Fri, 18 Jun 1999 23:54:59 +0000 Subject: [PATCH] checkpoint --- lib/dns/dispatch.c | 179 +++++++++++++++++++++++++++------ lib/dns/include/dns/dispatch.h | 23 ++--- 2 files changed, 159 insertions(+), 43 deletions(-) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 921fac8a4d..9605db2432 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -76,54 +76,147 @@ struct dns_dispatch { #define DISPATCH_MAGIC 0x69385829 /* "random" value */ #define VALID_DISPATCH(e) ((e) != NULL && (e)->magic == DISPATCH_MAGIC) -/* - * Initializes a response table. The hash table becomes 2^hashsize - * entries large. - * - * Requires: - * - * 0 <= "hashsize" <= 24. - * - * Returns: - * - * DNS_R_SUCCESS -- all is well. - * DNS_R_NOMEMORY -- not enough memory to allocate - */ -static dns_result_t -restable_initialize(dns_dispatch_t *disp, unsigned int hashsize) +dns_result_t +dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, + unsigned int maxbuffersize, + unsigned int maxbuffers, unsigned int maxrequests, + unsigned int hashsize, dns_dispatch_t **dispp) { - unsigned int count; + dns_dispatch_t *disp; + unsigned int tablesize; + dns_result_t res; + REQUIRE(mctx != NULL); + REQUIRE(sock != NULL); + REQUIRE(task != NULL); REQUIRE(hashsize <= 24); - INSIST(disp->qid_table == NULL); + REQUIRE(maxbuffersize >= 512 && maxbuffersize < (64*1024)); + REQUIRE(maxbuffers > 0); + REQUIRE(maxrequests <= maxbuffers); + REQUIRE(dispp != NULL && *dispp == NULL); - count = (1 << hashsize); + res = DNS_R_SUCCESS; - disp->qid_table = isc_mem_get(disp->mctx, count * sizeof(void *)); - if (disp->qid_table == NULL) + disp = isc_mem_get(mctx, sizeof(dns_dispatch_t)); + if (disp == NULL) return (DNS_R_NOMEMORY); - disp->qid_mask = count - 1; - disp->qid_hashsize = count; + disp->magic = 0; + disp->mctx = mctx; + disp->task = NULL; /* set below */ + disp->socket = NULL; /* set below */ + disp->buffersize = maxbuffersize; + + disp->refcount = 1; + + tablesize = (1 << hashsize); + + disp->qid_table = isc_mem_get(disp->mctx, tablesize * sizeof(void *)); + if (disp->qid_table == NULL) { + res = DNS_R_NOMEMORY; + goto out1; + } + + disp->qid_mask = tablesize - 1; + disp->qid_hashsize = tablesize; + + if (isc_mutex_init(&disp->lock) != ISC_R_SUCCESS) { + res = DNS_R_UNEXPECTED; + UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init failed"); + goto out2; + } + + if (isc_mempool_create(mctx, sizeof(dns_dispatchevent_t), + &disp->epool) != ISC_R_SUCCESS) { + res = DNS_R_NOMEMORY; + goto out3; + } + + if (isc_mempool_create(mctx, maxbuffersize, + &disp->bpool) != ISC_R_SUCCESS) { + res = DNS_R_NOMEMORY; + goto out4; + } + + if (isc_mempool_create(mctx, sizeof(dns_resentry_t), + &disp->rpool) != ISC_R_SUCCESS) { + res = DNS_R_NOMEMORY; + goto out5; + } + + /* + * should initialize qid_state here XXXMLG + */ + + disp->magic = DISPATCH_MAGIC; + + isc_task_attach(task, &disp->task); + isc_socket_attach(sock, &disp->socket); + + *dispp = disp; return (DNS_R_SUCCESS); + + /* + * error returns + */ + out5: + isc_mempool_destroy(&disp->rpool); + out4: + isc_mempool_destroy(&disp->bpool); + out3: + isc_mempool_destroy(&disp->epool); + out2: + isc_mem_put(mctx, disp->mctx, disp->qid_hashsize * sizeof(void *)); + out1: + isc_mem_put(mctx, disp, sizeof(dns_dispatch_t)); + + return (res); } /* - * Invalidate a ressponse table. - * - * Ensures: - * - * All internal resources are freed. + * Called when refcount reaches 0 at any time. */ static void -restable_invalidate(dns_dispatch_t *disp) +destroy(dns_dispatch_t *disp) { - REQUIRE(disp->qid_table != NULL); + disp->magic = 0; + isc_task_detach(&disp->task); + isc_socket_detach(&disp->socket); + + isc_mempool_destroy(&disp->rpool); + isc_mempool_destroy(&disp->bpool); + isc_mempool_destroy(&disp->epool); isc_mem_put(disp->mctx, disp->qid_table, disp->qid_hashsize * sizeof(void *)); - disp->qid_table = NULL; - disp->qid_hashsize = 0; + + isc_mem_put(disp->mctx, disp, sizeof(dns_dispatch_t)); +} + +void +dns_dispatch_destroy(dns_dispatch_t **dispp) +{ + dns_dispatch_t *disp; + isc_boolean_t killit; + + REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp)); + + disp = *dispp; + *dispp = NULL; + + killit = ISC_FALSE; + + LOCK(&disp->lock); + + INSIST(disp->refcount > 0); + disp->refcount--; + if (disp->refcount == 0) + killit = ISC_TRUE; + + UNLOCK(&disp->lock); + + if (killit) + destroy(disp); } dns_result_t @@ -145,6 +238,8 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest, LOCK(&disp->lock); + disp->refcount++; + /* * Try somewhat hard to find an unique ID. */ @@ -196,6 +291,7 @@ dns_dispatch_removeresponse(dns_dispatch_t *disp, dns_resentry_t **resp, dns_resentry_t *res; dns_dispatchevent_t *ev; unsigned int bucket; + isc_boolean_t killit; REQUIRE(VALID_DISPATCH(disp)); REQUIRE(resp != NULL); @@ -204,6 +300,8 @@ dns_dispatch_removeresponse(dns_dispatch_t *disp, dns_resentry_t **resp, res = *resp; *resp = NULL; + killit = ISC_FALSE; + if (sockevent != NULL) { REQUIRE(*sockevent != NULL); ev = *sockevent; @@ -214,6 +312,11 @@ dns_dispatch_removeresponse(dns_dispatch_t *disp, dns_resentry_t **resp, LOCK(&disp->lock); + INSIST(disp->refcount > 0); + disp->refcount--; + if (disp->refcount == 0) + killit = ISC_TRUE; + res->magic = 0; bucket = res->bucket; @@ -222,6 +325,9 @@ dns_dispatch_removeresponse(dns_dispatch_t *disp, dns_resentry_t **resp, isc_mempool_put(disp->rpool, res); UNLOCK(&disp->lock); + + if (killit) + destroy(disp); } dns_result_t @@ -264,6 +370,7 @@ dns_dispatch_removerequest(dns_dispatch_t *disp, dns_resentry_t **resp, { dns_resentry_t *res; dns_dispatchevent_t *ev; + isc_boolean_t killit; REQUIRE(VALID_DISPATCH(disp)); REQUIRE(resp != NULL); @@ -272,6 +379,8 @@ dns_dispatch_removerequest(dns_dispatch_t *disp, dns_resentry_t **resp, res = *resp; *resp = NULL; + killit = ISC_FALSE; + if (sockevent != NULL) { REQUIRE(*sockevent != NULL); ev = *sockevent; @@ -282,6 +391,11 @@ dns_dispatch_removerequest(dns_dispatch_t *disp, dns_resentry_t **resp, LOCK(&disp->lock); + INSIST(disp->refcount > 0); + disp->refcount--; + if (disp->refcount == 0) + killit = ISC_TRUE; + res->magic = 0; ISC_LIST_UNLINK(disp->rq_handlers, res, link); @@ -289,4 +403,7 @@ dns_dispatch_removerequest(dns_dispatch_t *disp, dns_resentry_t **resp, isc_mempool_put(disp->rpool, res); UNLOCK(&disp->lock); + + if (killit) + destroy(disp); } diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 5c2847a21a..f1abdf2839 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -61,7 +61,7 @@ ISC_LANG_BEGINDECLS * any buffer space allocated from common pools. */ typedef struct dns_dispatchevent dns_dispatchevent_t; -struct dns_dispatchevent_t { +struct dns_dispatchevent { ISC_EVENT_COMMON(dns_dispatchevent_t); /* standard event common */ dns_result_t result; /* result code */ isc_int16_t id; /* message id */ @@ -86,43 +86,42 @@ typedef struct dns_resentry dns_resentry_t; /* XXX name change */ dns_result_t dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, - unsigned int maxbuffersize, unsigned int copythresh, + unsigned int maxbuffersize, unsigned int maxbuffers, unsigned int maxrequests, - dns_dispatch_t **disp); + unsigned int hashsize, dns_dispatch_t **dispp); /* * Create a new dns_dispatch and attach it to the provided isc_socket_t. * * For all dispatches, "maxbuffersize" is the maximum packet size we will - * accept. For UDP packets, "copythresh" is the minimum size a packet - * needs to be before a copy is performed into a smaller, exactly sized - * buffer. "copythresh" is ignored for TCP packets, which always get an - * exactly sized buffer. + * accept. * * "maxbuffers" and "maxrequests" control the number of buffers in the * overall system and the number of buffers which can be allocated to * requests. * + * "hashsize" is the size of the hash table used to handle responses. The + * size is 2^hashsize, maximum of 2^24. + * * Requires: * * mctx is a valid memory context. * * sock is a valid. * - * taskmgr is a valid task manager. + * task is a valid task that can be used internally to this dispatcher. * * "buffersize" >= 512, which is the minimum receive size for a * DNS message. * - * For UDP sockets, "copythresh" <= "buffersize". If "copythresh" == 0, - * copying is never done, and if == UINT_MAX, copying is always done. - * * maxbuffers > 0. * * maxrequests <= maxbuffers. + * + * hashsize <= 24. */ void -dns_dispatch_destroy(dns_dispatch_t **disp); +dns_dispatch_destroy(dns_dispatch_t **dispp); /* * Destroys dispatch. All buffers and other bits must be returned to the * dispatch before this is called.