summaryrefslogtreecommitdiff
path: root/bin/named/lwdclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/named/lwdclient.c')
-rw-r--r--bin/named/lwdclient.c96
1 files changed, 72 insertions, 24 deletions
diff --git a/bin/named/lwdclient.c b/bin/named/lwdclient.c
index a8431340024c..511cbf0fb496 100644
--- a/bin/named/lwdclient.c
+++ b/bin/named/lwdclient.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007, 2015 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2000, 2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -59,12 +59,16 @@ ns_lwdclientmgr_create(ns_lwreslistener_t *listener, unsigned int nclients,
ns_lwdclientmgr_t *cm;
ns_lwdclient_t *client;
unsigned int i;
- isc_result_t result = ISC_R_FAILURE;
+ isc_result_t result;
cm = isc_mem_get(lwresd->mctx, sizeof(ns_lwdclientmgr_t));
if (cm == NULL)
return (ISC_R_NOMEMORY);
+ result = isc_mutex_init(&cm->lock);
+ if (result != ISC_R_SUCCESS)
+ goto freecm;
+
cm->listener = NULL;
ns_lwreslistener_attach(listener, &cm->listener);
cm->mctx = lwresd->mctx;
@@ -78,10 +82,10 @@ ns_lwdclientmgr_create(ns_lwreslistener_t *listener, unsigned int nclients,
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)
+ result = lwres_context_create(&cm->lwctx, cm->mctx,
+ ns__lwresd_memalloc, ns__lwresd_memfree,
+ LWRES_CONTEXT_SERVERMODE);
+ if (result != ISC_R_SUCCESS)
goto errout;
for (i = 0; i < nclients; i++) {
@@ -96,8 +100,10 @@ ns_lwdclientmgr_create(ns_lwreslistener_t *listener, unsigned int nclients,
/*
* If we could create no clients, clean up and return.
*/
- if (ISC_LIST_EMPTY(cm->idle))
+ if (ISC_LIST_EMPTY(cm->idle)) {
+ result = ISC_R_NOMEMORY;
goto errout;
+ }
result = isc_task_create(taskmgr, 0, &cm->task);
if (result != ISC_R_SUCCESS)
@@ -130,6 +136,9 @@ ns_lwdclientmgr_create(ns_lwreslistener_t *listener, unsigned int nclients,
if (cm->lwctx != NULL)
lwres_context_destroy(&cm->lwctx);
+ DESTROYLOCK(&cm->lock);
+
+ freecm:
isc_mem_put(lwresd->mctx, cm, sizeof(*cm));
return (result);
}
@@ -139,11 +148,14 @@ lwdclientmgr_destroy(ns_lwdclientmgr_t *cm) {
ns_lwdclient_t *client;
ns_lwreslistener_t *listener;
- if (!SHUTTINGDOWN(cm))
+ LOCK(&cm->lock);
+ if (!SHUTTINGDOWN(cm)) {
+ UNLOCK(&cm->lock);
return;
+ }
/*
- * run through the idle list and free the clients there. Idle
+ * 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.
*/
@@ -156,14 +168,20 @@ lwdclientmgr_destroy(ns_lwdclientmgr_t *cm) {
client = ISC_LIST_HEAD(cm->idle);
}
- if (!ISC_LIST_EMPTY(cm->running))
+ if (!ISC_LIST_EMPTY(cm->running)) {
+ UNLOCK(&cm->lock);
return;
+ }
+
+ UNLOCK(&cm->lock);
lwres_context_destroy(&cm->lwctx);
cm->view = NULL;
isc_socket_detach(&cm->sock);
isc_task_detach(&cm->task);
+ DESTROYLOCK(&cm->lock);
+
listener = cm->listener;
ns_lwreslistener_unlinkcm(listener, cm);
ns_lwdclient_log(50, "destroying manager %p", cm);
@@ -225,8 +243,10 @@ ns_lwdclient_recv(isc_task_t *task, isc_event_t *ev) {
NS_LWDCLIENT_SETRECVDONE(client);
+ LOCK(&cm->lock);
INSIST((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0);
cm->flags &= ~NS_LWDCLIENTMGR_FLAGRECVPENDING;
+ UNLOCK(&cm->lock);
ns_lwdclient_log(50,
"event received: task %p, length %u, result %u (%s)",
@@ -274,40 +294,53 @@ ns_lwdclient_startrecv(ns_lwdclientmgr_t *cm) {
ns_lwdclient_t *client;
isc_result_t result;
isc_region_t r;
+ isc_boolean_t destroy = ISC_FALSE;
+
+ LOCK(&cm->lock);
if (SHUTTINGDOWN(cm)) {
- lwdclientmgr_destroy(cm);
- return (ISC_R_SUCCESS);
+ destroy = ISC_TRUE;
+ result = ISC_R_SUCCESS;
+ goto unlock;
}
/*
* If a recv is already running, don't bother.
*/
- if ((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0)
- return (ISC_R_SUCCESS);
+ if ((cm->flags & NS_LWDCLIENTMGR_FLAGRECVPENDING) != 0) {
+ result = ISC_R_SUCCESS;
+ goto unlock;
+ }
/*
* If we have no idle slots, just return success.
*/
client = ISC_LIST_HEAD(cm->idle);
- if (client == NULL)
- return (ISC_R_SUCCESS);
+ if (client == NULL) {
+ result = ISC_R_SUCCESS;
+ goto unlock;
+ }
+
INSIST(NS_LWDCLIENT_ISIDLE(client));
/*
+ * Set the flag to say there is a recv pending. If isc_socket_recv
+ * fails we will clear the flag otherwise it will be cleared by
+ * ns_lwdclient_recv.
+ */
+ cm->flags |= NS_LWDCLIENTMGR_FLAGRECVPENDING;
+
+ /*
* Issue the recv. If it fails, return that it did.
*/
r.base = client->buffer;
r.length = LWRES_RECVLENGTH;
result = isc_socket_recv(cm->sock, &r, 0, cm->task, ns_lwdclient_recv,
client);
- if (result != ISC_R_SUCCESS)
- return (result);
-
- /*
- * Set the flag to say we've issued a recv() call.
- */
- cm->flags |= NS_LWDCLIENTMGR_FLAGRECVPENDING;
+ if (result != ISC_R_SUCCESS) {
+ cm->flags &= ~NS_LWDCLIENTMGR_FLAGRECVPENDING;
+ goto unlock;
+ }
/*
* Remove the client from the idle list, and put it on the running
@@ -317,7 +350,13 @@ ns_lwdclient_startrecv(ns_lwdclientmgr_t *cm) {
ISC_LIST_UNLINK(cm->idle, client, link);
ISC_LIST_APPEND(cm->running, client, link);
- return (ISC_R_SUCCESS);
+ unlock:
+ UNLOCK(&cm->lock);
+
+ if (destroy)
+ lwdclientmgr_destroy(cm);
+
+ return (result);
}
static void
@@ -335,6 +374,7 @@ lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev) {
* clients do not have a recv running nor do they have any finds
* or similar running.
*/
+ LOCK(&cm->lock);
client = ISC_LIST_HEAD(cm->idle);
while (client != NULL) {
ns_lwdclient_log(50, "destroying client %p, manager %p",
@@ -343,6 +383,7 @@ lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev) {
isc_mem_put(cm->mctx, client, sizeof(*client));
client = ISC_LIST_HEAD(cm->idle);
}
+ UNLOCK(&cm->lock);
/*
* Cancel any pending I/O.
@@ -353,6 +394,7 @@ lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev) {
* Run through the running client list and kill off any finds
* in progress.
*/
+ LOCK(&cm->lock);
client = ISC_LIST_HEAD(cm->running);
while (client != NULL) {
if (client->find != client->v4find
@@ -367,6 +409,8 @@ lwdclientmgr_shutdown_callback(isc_task_t *task, isc_event_t *ev) {
cm->flags |= NS_LWDCLIENTMGR_FLAGSHUTTINGDOWN;
+ UNLOCK(&cm->lock);
+
isc_event_free(&ev);
}
@@ -387,8 +431,10 @@ ns_lwdclient_stateidle(ns_lwdclient_t *client) {
INSIST(client->v4find == NULL);
INSIST(client->v6find == NULL);
+ LOCK(&cm->lock);
ISC_LIST_UNLINK(cm->running, client, link);
ISC_LIST_PREPEND(cm->idle, client, link);
+ UNLOCK(&cm->lock);
NS_LWDCLIENT_SETIDLE(client);
@@ -464,5 +510,7 @@ ns_lwdclient_initialize(ns_lwdclient_t *client, ns_lwdclientmgr_t *cmgr) {
client->pktinfo_valid = ISC_FALSE;
+ LOCK(&cmgr->lock);
ISC_LIST_APPEND(cmgr->idle, client, link);
+ UNLOCK(&cmgr->lock);
}