diff --git a/bin/named/include/named/lwdclient.h b/bin/named/include/named/lwdclient.h index eaa11f2ac0..100d6b0739 100644 --- a/bin/named/include/named/lwdclient.h +++ b/bin/named/include/named/lwdclient.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lwdclient.h,v 1.5 2000/08/01 01:12:09 tale Exp $ */ +/* $Id: lwdclient.h,v 1.6 2000/09/07 21:54:39 explorer Exp $ */ #ifndef NAMED_LWDCLIENT_H #define NAMED_LWDCLIENT_H 1 @@ -161,12 +161,14 @@ struct ns_lwdclient { ((c)->state = NS_LWDCLIENT_STATESENDDONE) struct ns_lwdclientmgr { + ns_lwresd_t *lwresd; isc_mem_t *mctx; - isc_task_t *task; /* owning task */ isc_socket_t *sock; /* socket to use */ dns_view_t *view; - unsigned int flags; lwres_context_t *lwctx; /* lightweight proto context */ + isc_task_t *task; /* owning task */ + unsigned int flags; + ISC_LINK(ns_lwdclientmgr_t) link; ISC_LIST(ns_lwdclient_t) idle; /* idle client slots */ ISC_LIST(ns_lwdclient_t) running; /* running clients */ }; @@ -174,6 +176,9 @@ struct ns_lwdclientmgr { #define NS_LWDCLIENTMGR_FLAGRECVPENDING 0x00000001 #define NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN 0x00000002 +void +ns_lwdclientmgr_create(ns_lwresd_t *, unsigned int, isc_taskmgr_t *); + void ns_lwdclient_initialize(ns_lwdclient_t *, ns_lwdclientmgr_t *); diff --git a/bin/named/include/named/lwresd.h b/bin/named/include/named/lwresd.h index 695f2d34fd..4809827b2f 100644 --- a/bin/named/include/named/lwresd.h +++ b/bin/named/include/named/lwresd.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lwresd.h,v 1.5 2000/08/01 01:12:10 tale Exp $ */ +/* $Id: lwresd.h,v 1.6 2000/09/07 21:54:40 explorer Exp $ */ #ifndef NAMED_LWRESD_H #define NAMED_LWRESD_H 1 @@ -27,19 +27,35 @@ struct ns_lwresd { isc_uint32_t magic; - ns_lwdclientmgr_t *cmgr; + + isc_mutex_t lock; + ISC_LIST(ns_lwdclientmgr_t) cmgrs; isc_socket_t *sock; - unsigned int ntasks; dns_view_t *view; isc_mem_t *mctx; - isc_task_t *task; dns_dispatchmgr_t *dispmgr; + isc_boolean_t shutting_down; }; void ns_lwresd_create(isc_mem_t *mctx, dns_view_t *view, ns_lwresd_t **lwresdp); +/* + * Trigger shutdown. + */ void -ns_lwresd_destroy(ns_lwresd_t **lwresdp); +ns_lwresd_shutdown(ns_lwresd_t **lwresdp); + +/* + * INTERNAL FUNCTIONS. + */ +void +lwresd_destroy(ns_lwresd_t *lwresdp); + +void * +ns_lwresd_memalloc(void *arg, size_t size); + +void +ns_lwresd_memfree(void *arg, void *mem, size_t size); #endif /* NAMED_LWRESD_H */ diff --git a/bin/named/lwdclient.c b/bin/named/lwdclient.c index 89486b03eb..0edf9b8dc9 100644 --- a/bin/named/lwdclient.c +++ b/bin/named/lwdclient.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lwdclient.c,v 1.6 2000/08/01 01:11:45 tale Exp $ */ +/* $Id: lwdclient.c,v 1.7 2000/09/07 21:54:35 explorer Exp $ */ #include @@ -24,12 +24,19 @@ #include #include +#include #include #include #include +#include #include +#define SHUTTINGDOWN(cm) ((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) != 0) + +static void +lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev); + void ns_lwdclient_log(int level, const char *format, ...) { va_list args; @@ -41,18 +48,124 @@ ns_lwdclient_log(int level, const char *format, ...) { va_end(args); } -static void -clientmgr_can_die(ns_lwdclientmgr_t *cm) { - if ((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) == 0) +void +ns_lwdclientmgr_create(ns_lwresd_t *lwresd, unsigned int nclients, + isc_taskmgr_t *taskmgr) +{ + ns_lwdclientmgr_t *cm; + ns_lwdclient_t *client; + unsigned int i; + + cm = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclientmgr_t)); + if (cm == NULL) return; - if (ISC_LIST_HEAD(cm->running) != NULL) + cm->lwresd = lwresd; + cm->mctx = lwresd->mctx; + cm->sock = lwresd->sock; + cm->view = lwresd->view; + cm->lwctx = NULL; + cm->task = NULL; + cm->flags = 0; + ISC_LINK_INIT(cm, link); + ISC_LIST_INIT(cm->idle); + ISC_LIST_INIT(cm->running); + + if (lwres_context_create(&cm->lwctx, cm->mctx, + ns_lwresd_memalloc, ns_lwresd_memfree, + LWRES_CONTEXT_SERVERMODE) + != ISC_R_SUCCESS) + goto errout; + + for (i = 0 ; i < nclients ; i++) { + client = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclient_t)); + if (client != NULL) { + ns_lwdclient_log(50, "created client %p, manager %p", + client, cm); + ns_lwdclient_initialize(client, cm); + } + } + + /* + * If we could create no clients, clean up and return. + */ + if (ISC_LIST_EMPTY(cm->idle)) + goto errout; + + if (isc_task_create(taskmgr, 0, &cm->task) != ISC_R_SUCCESS) + goto errout; + + /* + * This MUST be last, since there is no way to cancel an onshutdown... + */ + if (isc_task_onshutdown(cm->task, lwdclientmgr_shutdown_callback, cm) + != ISC_R_SUCCESS) + goto errout; + + /* + * Nothing between the onshutdown call and the end of this + * function is allowed to fail without crashing the server + * via INSIST() or REQUIRE(). + */ + + ISC_LIST_APPEND(lwresd->cmgrs, cm, link); + + return; + + errout: + client = ISC_LIST_HEAD(cm->idle); + while (client != NULL) { + ISC_LIST_UNLINK(cm->idle, client, link); + isc_mem_put(lwresd->mctx, client, sizeof (*client)); + client = ISC_LIST_HEAD(cm->idle); + } + + if (cm->task != NULL) + isc_task_detach(&cm->task); + + if (cm->lwctx != NULL) + lwres_context_destroy(&cm->lwctx); + + isc_mem_put(lwresd->mctx, cm, sizeof (*cm)); +} + +static void +lwdclientmgr_destroy(ns_lwdclientmgr_t *cm) { + ns_lwdclient_t *client; + ns_lwresd_t *lwresd = cm->lwresd; + + if (!SHUTTINGDOWN(cm)) + return; + + /* + * run through the idle list and free the clients there. Idle + * clients do not have a recv running nor do they have any finds + * or similar running. + */ + client = ISC_LIST_HEAD(cm->idle); + while (client != NULL) { + ns_lwdclient_log(50, "destroying client %p, manager %p", + client, cm); + ISC_LIST_UNLINK(cm->idle, client, link); + isc_mem_put(cm->mctx, client, sizeof (*client)); + client = ISC_LIST_HEAD(cm->idle); + } + + if (!ISC_LIST_EMPTY(cm->running)) return; lwres_context_destroy(&cm->lwctx); - isc_socket_detach(&cm->sock); - dns_view_detach(&cm->view); + cm->view = NULL; + cm->sock = NULL; isc_task_detach(&cm->task); + + LOCK(&lwresd->lock); + ISC_LIST_UNLINK(lwresd->cmgrs, cm, link); + ns_lwdclient_log(50, "destroying manager %p", cm); + isc_mem_put(lwresd->mctx, cm, sizeof (*cm)); + UNLOCK(&lwresd->lock); + + lwresd_destroy(lwresd); } static void @@ -148,8 +261,10 @@ ns_lwdclient_startrecv(ns_lwdclientmgr_t *cm) { isc_result_t result; isc_region_t r; - if ((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) != 0) + if (SHUTTINGDOWN(cm)) { + lwdclientmgr_destroy(cm); return (ISC_R_SUCCESS); + } /* * If a recv is already running, don't bother. @@ -191,25 +306,50 @@ ns_lwdclient_startrecv(ns_lwdclientmgr_t *cm) { return (ISC_R_SUCCESS); } -void -ns_lwdclient_shutdown(isc_task_t *task, isc_event_t *ev) { +static void +lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev) { ns_lwdclientmgr_t *cm = ev->ev_arg; + ns_lwdclient_t *client; - REQUIRE((cm->flags & NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN) == 0); + REQUIRE(!SHUTTINGDOWN(cm)); - ns_lwdclient_log(50, "got shutdown event, task %p", task); + ns_lwdclient_log(50, "got shutdown event, task %p, lwdclientmgr %p", + task, cm); + + /* + * run through the idle list and free the clients there. Idle + * clients do not have a recv running nor do they have any finds + * or similar running. + */ + client = ISC_LIST_HEAD(cm->idle); + while (client != NULL) { + ns_lwdclient_log(50, "destroying client %p, manager %p", + client, cm); + ISC_LIST_UNLINK(cm->idle, client, link); + isc_mem_put(cm->mctx, client, sizeof (*client)); + client = ISC_LIST_HEAD(cm->idle); + } /* * Cancel any pending I/O. */ - if ((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0) - isc_socket_cancel(cm->sock, task, ISC_SOCKCANCEL_ALL); + isc_socket_cancel(cm->sock, task, ISC_SOCKCANCEL_ALL); /* * Run through the running client list and kill off any finds * in progress. */ - /* XXXMLG */ + client = ISC_LIST_HEAD(cm->running); + while (client != NULL) { + if (client->find != client->v4find + && client->find != client->v6find) + dns_adb_cancelfind(client->find); + if (client->v4find != NULL) + dns_adb_cancelfind(client->v4find); + if (client->v6find != NULL) + dns_adb_cancelfind(client->v6find); + client = ISC_LIST_NEXT(client, link); + } cm->flags |= NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN; @@ -237,8 +377,6 @@ ns_lwdclient_stateidle(ns_lwdclient_t *client) { NS_LWDCLIENT_SETIDLE(client); - clientmgr_can_die(cm); - ns_lwdclient_startrecv(cm); } diff --git a/bin/named/lwresd.c b/bin/named/lwresd.c index f2d87f7437..f7d3b24496 100644 --- a/bin/named/lwresd.c +++ b/bin/named/lwresd.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: lwresd.c,v 1.14 2000/08/24 22:15:26 bwelling Exp $ */ +/* $Id: lwresd.c,v 1.15 2000/09/07 21:54:36 explorer Exp $ */ /* * Main program for the Lightweight Resolver Daemon. @@ -60,9 +60,8 @@ /* * The goal number of clients we can handle will be NTASKS * NRECVS. */ -#define NTASKS 20 /* tasks to create to handle lwres queries */ -#define NRECVS 5 /* max clients per task */ -#define NTHREADS 1 /* # threads to create in thread manager */ +#define NTASKS 2 /* tasks to create to handle lwres queries */ +#define NRECVS 2 /* max clients per task */ static void fatal(const char *msg, isc_result_t result) { @@ -77,41 +76,43 @@ fatal(const char *msg, isc_result_t result) { /* * Wrappers around our memory management stuff, for the lwres functions. */ -static void * -mem_alloc(void *arg, size_t size) { +void * +ns_lwresd_memalloc(void *arg, size_t size) { return (isc_mem_get(arg, size)); } -static void -mem_free(void *arg, void *mem, size_t size) { +void +ns_lwresd_memfree(void *arg, void *mem, size_t size) { isc_mem_put(arg, mem, size); } -static void -shutdown_lwresd(isc_task_t *task, isc_event_t *event) { - ns_lwresd_t *lwresd = event->ev_arg; +void +lwresd_destroy(ns_lwresd_t *lwresd) { + isc_mem_t *mctx; - UNUSED(task); + LOCK(&lwresd->lock); + if (!ISC_LIST_EMPTY(lwresd->cmgrs) || (!lwresd->shutting_down)) { + UNLOCK(&lwresd->lock); + return; + } + + /* + * At this point, nothing can have the lwresd locked, since there + * are no clients running. + */ + UNLOCK(&lwresd->lock); dns_dispatchmgr_destroy(&lwresd->dispmgr); - - /* - * Wait for everything to die off by waiting for the sockets - * to be detached. - */ isc_socket_detach(&lwresd->sock); - - /* - * Kill off the view. - */ dns_view_detach(&lwresd->view); - isc_task_detach(&lwresd->task); + mctx = lwresd->mctx; - isc_event_free(&event); + lwresd->magic = 0; + isc_mem_put(mctx, lwresd, sizeof(*lwresd)); + isc_mem_detach(&mctx); } - static void parse_resolv_conf(isc_mem_t *mctx, isc_sockaddrlist_t *forwarders) { lwres_context_t *lwctx; @@ -124,7 +125,7 @@ parse_resolv_conf(isc_mem_t *mctx, isc_sockaddrlist_t *forwarders) { in_port_t port; lwctx = NULL; - lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, + lwresult = lwres_context_create(&lwctx, mctx, ns_lwresd_memalloc, ns_lwresd_memfree, LWRES_CONTEXT_SERVERMODE); if (lwresult != LWRES_R_SUCCESS) return; @@ -296,8 +297,8 @@ ns_lwresd_create(isc_mem_t *mctx, dns_view_t *view, ns_lwresd_t **lwresdp) { ns_lwresd_t *lwresd; isc_sockaddr_t localhost; struct in_addr lh_addr; - unsigned int i, j; - ns_lwdclient_t *client; + unsigned int i; + ns_lwdclientmgr_t *cm; isc_socket_t *sock; isc_result_t result; @@ -322,15 +323,21 @@ ns_lwresd_create(isc_mem_t *mctx, dns_view_t *view, ns_lwresd_t **lwresdp) { lwresd = isc_mem_get(mctx, sizeof(*lwresd)); if (lwresd == NULL) - fatal("allocating lightweight resolver object", ISC_R_NOMEMORY); + fatal("allocating lightweight resolver object", + ISC_R_NOMEMORY); lwresd->mctx = NULL; isc_mem_attach(mctx, &lwresd->mctx); - lwresd->sock = sock; + result = isc_mutex_init(&lwresd->lock); + if (result != ISC_R_SUCCESS) + fatal("creating lock", result); + lwresd->shutting_down = ISC_FALSE; + lwresd->sock = sock; lwresd->view = NULL; lwresd->dispmgr = NULL; + ISC_LIST_INIT(lwresd->cmgrs); if (view != NULL) dns_view_attach(view, &lwresd->view); else { @@ -339,115 +346,50 @@ ns_lwresd_create(isc_mem_t *mctx, dns_view_t *view, ns_lwresd_t **lwresdp) { fatal("failed to create default view", result); } - lwresd->task = NULL; - result = isc_task_create(ns_g_taskmgr, 0, &lwresd->task); - if (result != ISC_R_SUCCESS) - fatal("allocating lightweight resolver task", result); - isc_task_setname(lwresd->task, "lwresd", lwresd); - result = isc_task_onshutdown(lwresd->task, shutdown_lwresd, lwresd); - if (result != ISC_R_SUCCESS) - fatal("allocating lwresd onshutdown event", result); - - lwresd->cmgr = isc_mem_get(lwresd->mctx, - sizeof(ns_lwdclientmgr_t) * NTASKS); - if (lwresd->cmgr == NULL) - fatal("allocating lwresd client manager", ISC_R_NOMEMORY); + /* + * Create the managers. + */ + for (i = 0 ; i < NTASKS ; i++) + ns_lwdclientmgr_create(lwresd, NRECVS, ns_g_taskmgr); /* - * Create one task for each client manager. + * Ensure that we have created at least one. */ - for (i = 0 ; i < NTASKS ; i++) { - char name[16]; - lwresd->cmgr[i].task = NULL; - lwresd->cmgr[i].sock = NULL; - isc_socket_attach(lwresd->sock, &lwresd->cmgr[i].sock); - lwresd->cmgr[i].view = NULL; - lwresd->cmgr[i].flags = 0; - result = isc_task_create(ns_g_taskmgr, 0, - &lwresd->cmgr[i].task); - if (result != ISC_R_SUCCESS) - break; - result = isc_task_onshutdown(lwresd->cmgr[i].task, - ns_lwdclient_shutdown, - &lwresd->cmgr[i]); - if (result != ISC_R_SUCCESS) - break; - ISC_LIST_INIT(lwresd->cmgr[i].idle); - ISC_LIST_INIT(lwresd->cmgr[i].running); - snprintf(name, sizeof(name), "lwd client %d", i); - isc_task_setname(lwresd->cmgr[i].task, name, &lwresd->cmgr[i]); - lwresd->cmgr[i].mctx = lwresd->mctx; - lwresd->cmgr[i].lwctx = NULL; - result = lwres_context_create(&lwresd->cmgr[i].lwctx, - lwresd->mctx, - mem_alloc, mem_free, - LWRES_CONTEXT_SERVERMODE); - if (result != ISC_R_SUCCESS) { - isc_task_detach(&lwresd->cmgr[i].task); - break; - } - dns_view_attach(lwresd->view, &lwresd->cmgr[i].view); - } - INSIST(i > 0); - lwresd->ntasks = i; /* remember how many we managed to create */ + INSIST(!ISC_LIST_EMPTY(lwresd->cmgrs)); /* - * Now, run through each client manager and populate it with - * client structures. Do this by creating one receive for each - * task, in a loop, so each task has a chance of getting at least - * one client structure. + * Walk the list of clients and start each one up. */ - for (i = 0 ; i < NRECVS ; i++) { - client = isc_mem_get(lwresd->mctx, - sizeof(ns_lwdclient_t) * lwresd->ntasks); - if (client == NULL) - break; - for (j = 0 ; j < lwresd->ntasks ; j++) - ns_lwdclient_initialize(&client[j], &lwresd->cmgr[j]); - } - INSIST(i > 0); - - /* - * Issue one read request for each task we have. - */ - for (j = 0 ; j < lwresd->ntasks ; j++) { - result = ns_lwdclient_startrecv(&lwresd->cmgr[j]); - INSIST(result == ISC_R_SUCCESS); + LOCK(&lwresd->lock); + cm = ISC_LIST_HEAD(lwresd->cmgrs); + while (cm != NULL) { + ns_lwdclient_startrecv(cm); + cm = ISC_LIST_NEXT(cm, link); } + UNLOCK(&lwresd->lock); lwresd->magic = LWRESD_MAGIC; *lwresdp = lwresd; } void -ns_lwresd_destroy(ns_lwresd_t **lwresdp) { +ns_lwresd_shutdown(ns_lwresd_t **lwresdp) { + ns_lwdclientmgr_t *cm; ns_lwresd_t *lwresd; - ns_lwdclient_t *client; - isc_mem_t *mctx; - REQUIRE(lwresdp != NULL); + INSIST(lwresdp != NULL && VALID_LWRESD(*lwresdp)); + lwresd = *lwresdp; - REQUIRE(VALID_LWRESD(lwresd)); - - mctx = lwresd->mctx; - - /* - * Free up memory allocated. This is somewhat magical. We allocated - * the ns_lwdclient_t's in blocks, but the first task always has the - * first pointer. Just loop here, freeing them. - */ - client = ISC_LIST_HEAD(lwresd->cmgr[0].idle); - while (client != NULL) { - ISC_LIST_UNLINK(lwresd->cmgr[0].idle, client, link); - isc_mem_put(mctx, client, - sizeof(ns_lwdclient_t) * lwresd->ntasks); - client = ISC_LIST_HEAD(lwresd->cmgr[0].idle); - } - INSIST(ISC_LIST_EMPTY(lwresd->cmgr[0].running)); - - isc_mem_put(mctx, lwresd->cmgr, sizeof(ns_lwdclientmgr_t) * NTASKS); - lwresd->magic = 0; - isc_mem_put(mctx, lwresd, sizeof(*lwresd)); - isc_mem_detach(&mctx); *lwresdp = NULL; + + LOCK(&lwresd->lock); + lwresd->shutting_down = ISC_TRUE; + cm = ISC_LIST_HEAD(lwresd->cmgrs); + while (cm != NULL) { + isc_task_shutdown(cm->task); + cm = ISC_LIST_NEXT(cm, link); + } + UNLOCK(&lwresd->lock); + + lwresd_destroy(lwresd); } diff --git a/bin/named/main.c b/bin/named/main.c index 499abaf590..e134fc043c 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: main.c,v 1.82 2000/08/30 20:40:04 bwelling Exp $ */ +/* $Id: main.c,v 1.83 2000/09/07 21:54:37 explorer Exp $ */ #include @@ -518,11 +518,12 @@ setup(void) { static void cleanup(void) { + if (lwresd_only) + ns_lwresd_shutdown(&ns_g_lwresd); + destroy_managers(); - if (lwresd_only) - ns_lwresd_destroy(&ns_g_lwresd); - else + if (!lwresd_only) ns_server_destroy(&ns_g_server); isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,