* the dying client inbetween.
*/
client->state = NS_CLIENTSTATE_INACTIVE;
- if (!ns_g_clienttest)
- ISC_QUEUE_PUSH(manager->inactive, client, ilink);
INSIST(client->recursionquota == NULL);
if (client->state == client->newstate) {
client->newstate = NS_CLIENTSTATE_MAX;
+ if (!ns_g_clienttest && manager != NULL &&
+ !manager->exiting)
+ ISC_QUEUE_PUSH(manager->inactive, client,
+ ilink);
if (client->needshutdown)
isc_task_shutdown(client->task);
return (ISC_TRUE);
REQUIRE(client->state == NS_CLIENTSTATE_INACTIVE);
INSIST(client->recursionquota == NULL);
+ INSIST(!ISC_QLINK_LINKED(client, ilink));
ns_query_free(client);
isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE);
client->shutdown_arg = NULL;
}
+ if (ISC_QLINK_LINKED(client, ilink))
+ ISC_QUEUE_UNLINK(client->manager->inactive, client, ilink);
+
client->newstate = NS_CLIENTSTATE_FREED;
client->needshutdown = ISC_FALSE;
(void)exit_check(client);
#ifdef ALLOW_FILTER_AAAA_ON_V4
client->filter_aaaa = dns_v4_aaaa_ok;
#endif
+ client->needshutdown = ns_g_clienttest;
+
ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL,
NS_EVENT_CLIENTCONTROL, client_start, client, client,
NULL, NULL);
if (result != ISC_R_SUCCESS)
goto cleanup_query;
- client->needshutdown = ns_g_clienttest;
-
CTRACE("create");
*clientp = client;
void
ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
+ isc_result_t result;
ns_clientmgr_t *manager;
ns_client_t *client;
- isc_boolean_t need_destroy = ISC_FALSE;
+ isc_boolean_t need_destroy = ISC_FALSE, unlock = ISC_FALSE;
REQUIRE(managerp != NULL);
manager = *managerp;
MTRACE("destroy");
- LOCK(&manager->listlock);
+ /*
+ * Check for success because we may already be task-exclusive
+ * at this point. Only if we succeed at obtaining an exclusive
+ * lock now will we need to relinquish it later.
+ */
+ result = isc_task_beginexclusive(ns_g_server->task);
+ if (result == ISC_R_SUCCESS)
+ unlock = ISC_TRUE;
- LOCK(&manager->lock);
manager->exiting = ISC_TRUE;
- UNLOCK(&manager->lock);
for (client = ISC_LIST_HEAD(manager->clients);
client != NULL;
if (ISC_LIST_EMPTY(manager->clients))
need_destroy = ISC_TRUE;
- UNLOCK(&manager->listlock);
+ if (unlock)
+ isc_task_endexclusive(ns_g_server->task);
if (need_destroy)
clientmgr_destroy(manager);
ns_client_t *client;
MTRACE("get client");
+ if (manager != NULL && manager->exiting)
+ return (ISC_R_SHUTTINGDOWN);
+
/*
* Allocate a client. First try to get a recycled one;
* if that fails, make a new one.
#define ISC_QLINK_INSIST(x) (void)0
#endif
-#define ISC_QLINK(type) struct { void *prev, *next; }
+#define ISC_QLINK(type) struct { type *prev, *next; }
#define ISC_QLINK_INIT(elt, link) \
do { \
(ret)->link.next = (ret)->link.prev = (void *)(-1); \
} while(0)
+#define ISC_QUEUE_UNLINK(queue, elt, link) \
+ do { \
+ ISC_QLINK_INSIST(ISC_QLINK_LINKED(elt, link)); \
+ LOCK(&(queue).headlock); \
+ LOCK(&(queue).taillock); \
+ if ((elt)->link.prev == NULL) \
+ (queue).head = (elt)->link.next; \
+ else \
+ (elt)->link.prev->link.next = (elt)->link.next; \
+ if ((elt)->link.next == NULL) \
+ (queue).tail = (elt)->link.prev; \
+ else \
+ (elt)->link.next->link.prev = (elt)->link.prev; \
+ UNLOCK(&(queue).taillock); \
+ UNLOCK(&(queue).headlock); \
+ (elt)->link.next = (elt)->link.prev = (void *)(-1); \
+ } while(0)
+
#endif /* ISC_QUEUE_H */
#include "isctest.h"
-typedef struct item {
+typedef struct item item_t;
+struct item {
int value;
ISC_QLINK(item_t) qlink;
-} item_t;
+};
typedef ISC_QUEUE(item_t) item_queue_t;
ISC_QUEUE_PUSH(queue, &five, qlink);
ATF_CHECK(ISC_QLINK_LINKED(&five, qlink));
+ /* Test unlink by removing one item from the middle */
+ ISC_QUEUE_UNLINK(queue, &three, qlink);
+
ISC_QUEUE_POP(queue, qlink, p);
ATF_REQUIRE(p != NULL);
ATF_CHECK_EQ(p->value, 1);
ATF_REQUIRE(p != NULL);
ATF_CHECK_EQ(p->value, 2);
- ISC_QUEUE_POP(queue, qlink, p);
- ATF_REQUIRE(p != NULL);
- ATF_CHECK_EQ(p->value, 3);
-
ISC_QUEUE_POP(queue, qlink, p);
ATF_REQUIRE(p != NULL);
ATF_CHECK_EQ(p->value, 4);