mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-01 15:05:23 +00:00
revise shutdown process
This commit is contained in:
@@ -198,6 +198,7 @@ struct dns_resolver {
|
|||||||
/* Locked by lock. */
|
/* Locked by lock. */
|
||||||
unsigned int references;
|
unsigned int references;
|
||||||
isc_boolean_t exiting;
|
isc_boolean_t exiting;
|
||||||
|
isc_eventlist_t whenshutdown;
|
||||||
isc_socket_t * udpsocket4;
|
isc_socket_t * udpsocket4;
|
||||||
isc_socket_t * udpsocket6;
|
isc_socket_t * udpsocket6;
|
||||||
dns_dispatch_t * dispatch4;
|
dns_dispatch_t * dispatch4;
|
||||||
@@ -1135,7 +1136,8 @@ fctx_destroy(fetchctx_t *fctx) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
REQUIRE(VALID_FCTX(fctx));
|
REQUIRE(VALID_FCTX(fctx));
|
||||||
REQUIRE(fctx->state == fetchstate_done);
|
REQUIRE(fctx->state == fetchstate_done ||
|
||||||
|
fctx->state == fetchstate_init);
|
||||||
REQUIRE(ISC_LIST_EMPTY(fctx->events));
|
REQUIRE(ISC_LIST_EMPTY(fctx->events));
|
||||||
REQUIRE(ISC_LIST_EMPTY(fctx->queries));
|
REQUIRE(ISC_LIST_EMPTY(fctx->queries));
|
||||||
REQUIRE(ISC_LIST_EMPTY(fctx->finds));
|
REQUIRE(ISC_LIST_EMPTY(fctx->finds));
|
||||||
@@ -1195,7 +1197,39 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fctx_shutdown(isc_task_t *task, isc_event_t *event) {
|
fctx_shutdown(fetchctx_t *fctx) {
|
||||||
|
isc_event_t *cevent;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the shutdown process for fctx, if it isn't already underway.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FCTXTRACE("shutdown");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The caller must be holding the appropriate bucket lock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (fctx->want_shutdown)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fctx->want_shutdown = ISC_TRUE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unless we're still initializing (in which case the
|
||||||
|
* control event is still outstanding), we need to post
|
||||||
|
* the control event to tell the fetch we want it to
|
||||||
|
* exit.
|
||||||
|
*/
|
||||||
|
if (fctx->state != fetchstate_init) {
|
||||||
|
cevent = &fctx->control_event;
|
||||||
|
isc_task_send(fctx->res->buckets[fctx->bucketnum].task,
|
||||||
|
&cevent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
|
||||||
fetchctx_t *fctx = event->arg;
|
fetchctx_t *fctx = event->arg;
|
||||||
isc_boolean_t bucket_empty = ISC_FALSE;
|
isc_boolean_t bucket_empty = ISC_FALSE;
|
||||||
dns_resolver_t *res;
|
dns_resolver_t *res;
|
||||||
@@ -1207,7 +1241,7 @@ fctx_shutdown(isc_task_t *task, isc_event_t *event) {
|
|||||||
bucketnum = fctx->bucketnum;
|
bucketnum = fctx->bucketnum;
|
||||||
(void)task; /* Keep compiler quiet. */
|
(void)task; /* Keep compiler quiet. */
|
||||||
|
|
||||||
FCTXTRACE("shutdown");
|
FCTXTRACE("doshutdown");
|
||||||
|
|
||||||
fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
|
fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
|
||||||
|
|
||||||
@@ -1270,8 +1304,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) {
|
|||||||
* the fctx.
|
* the fctx.
|
||||||
*/
|
*/
|
||||||
ISC_EVENT_INIT(event, sizeof *event, 0, NULL,
|
ISC_EVENT_INIT(event, sizeof *event, 0, NULL,
|
||||||
DNS_EVENT_FETCHCONTROL, fctx_shutdown, fctx,
|
DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx,
|
||||||
(void *)fctx_shutdown, NULL, NULL);
|
(void *)fctx_doshutdown, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNLOCK(&res->buckets[bucketnum].lock);
|
UNLOCK(&res->buckets[bucketnum].lock);
|
||||||
@@ -2920,9 +2954,27 @@ destroy(dns_resolver_t *res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
empty_bucket(dns_resolver_t *res) {
|
send_shutdown_events(dns_resolver_t *res) {
|
||||||
isc_boolean_t need_destroy = ISC_FALSE;
|
isc_event_t *event, *next_event;
|
||||||
|
isc_task_t *etask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Caller must be holding the resolver lock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (event = ISC_LIST_HEAD(res->whenshutdown);
|
||||||
|
event != NULL;
|
||||||
|
event = next_event) {
|
||||||
|
next_event = ISC_LIST_NEXT(event, link);
|
||||||
|
ISC_LIST_UNLINK(res->whenshutdown, event, link);
|
||||||
|
etask = event->sender;
|
||||||
|
event->sender = res;
|
||||||
|
isc_task_sendanddetach(&etask, &event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
empty_bucket(dns_resolver_t *res) {
|
||||||
RTRACE("empty_bucket");
|
RTRACE("empty_bucket");
|
||||||
|
|
||||||
LOCK(&res->lock);
|
LOCK(&res->lock);
|
||||||
@@ -2930,12 +2982,9 @@ empty_bucket(dns_resolver_t *res) {
|
|||||||
INSIST(res->activebuckets > 0);
|
INSIST(res->activebuckets > 0);
|
||||||
res->activebuckets--;
|
res->activebuckets--;
|
||||||
if (res->activebuckets == 0)
|
if (res->activebuckets == 0)
|
||||||
need_destroy = ISC_TRUE;
|
send_shutdown_events(res);
|
||||||
|
|
||||||
UNLOCK(&res->lock);
|
UNLOCK(&res->lock);
|
||||||
|
|
||||||
if (need_destroy)
|
|
||||||
destroy(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
@@ -3048,6 +3097,7 @@ dns_resolver_create(dns_view_t *view,
|
|||||||
|
|
||||||
res->references = 1;
|
res->references = 1;
|
||||||
res->exiting = ISC_FALSE;
|
res->exiting = ISC_FALSE;
|
||||||
|
ISC_LIST_INIT(res->whenshutdown);
|
||||||
|
|
||||||
result = isc_mutex_init(&res->lock);
|
result = isc_mutex_init(&res->lock);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
@@ -3108,27 +3158,57 @@ dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_resolver_detach(dns_resolver_t **resp) {
|
dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task,
|
||||||
dns_resolver_t *res;
|
isc_event_t **eventp)
|
||||||
isc_boolean_t need_destroy = ISC_FALSE;
|
{
|
||||||
unsigned int i;
|
isc_task_t *clone;
|
||||||
|
isc_event_t *event;
|
||||||
|
|
||||||
|
REQUIRE(VALID_RESOLVER(res));
|
||||||
|
REQUIRE(eventp != NULL);
|
||||||
|
|
||||||
|
event = *eventp;
|
||||||
|
*eventp = NULL;
|
||||||
|
|
||||||
|
LOCK(&res->lock);
|
||||||
|
|
||||||
|
if (res->exiting && res->activebuckets == 0) {
|
||||||
|
/*
|
||||||
|
* We're already shutdown. Send the event.
|
||||||
|
*/
|
||||||
|
event->sender = res;
|
||||||
|
isc_task_send(task, &event);
|
||||||
|
} else {
|
||||||
|
clone = NULL;
|
||||||
|
isc_task_attach(task, &clone);
|
||||||
|
event->sender = clone;
|
||||||
|
ISC_LIST_APPEND(res->whenshutdown, event, link);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK(&res->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_resolver_shutdown(dns_resolver_t *res) {
|
||||||
|
unsigned int i;
|
||||||
|
fetchctx_t *fctx;
|
||||||
|
|
||||||
REQUIRE(resp != NULL);
|
|
||||||
res = *resp;
|
|
||||||
REQUIRE(VALID_RESOLVER(res));
|
REQUIRE(VALID_RESOLVER(res));
|
||||||
|
|
||||||
RTRACE("detach");
|
RTRACE("shutdown");
|
||||||
|
|
||||||
LOCK(&res->lock);
|
LOCK(&res->lock);
|
||||||
INSIST(res->references > 0);
|
|
||||||
res->references--;
|
if (!res->exiting) {
|
||||||
if (res->references == 0) {
|
|
||||||
RTRACE("exiting");
|
RTRACE("exiting");
|
||||||
res->exiting = ISC_TRUE;
|
res->exiting = ISC_TRUE;
|
||||||
|
|
||||||
for (i = 0; i < res->nbuckets; i++) {
|
for (i = 0; i < res->nbuckets; i++) {
|
||||||
/*
|
|
||||||
* XXXRTH Post shutdown events?
|
|
||||||
*/
|
|
||||||
LOCK(&res->buckets[i].lock);
|
LOCK(&res->buckets[i].lock);
|
||||||
|
for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs);
|
||||||
|
fctx != NULL;
|
||||||
|
fctx = ISC_LIST_NEXT(fctx, link))
|
||||||
|
fctx_shutdown(fctx);
|
||||||
if (res->udpsocket4 != NULL)
|
if (res->udpsocket4 != NULL)
|
||||||
isc_socket_cancel(res->udpsocket4,
|
isc_socket_cancel(res->udpsocket4,
|
||||||
res->buckets[i].task,
|
res->buckets[i].task,
|
||||||
@@ -3145,8 +3225,40 @@ dns_resolver_detach(dns_resolver_t **resp) {
|
|||||||
UNLOCK(&res->buckets[i].lock);
|
UNLOCK(&res->buckets[i].lock);
|
||||||
}
|
}
|
||||||
if (res->activebuckets == 0)
|
if (res->activebuckets == 0)
|
||||||
need_destroy = ISC_TRUE;
|
send_shutdown_events(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UNLOCK(&res->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXXRTH Do we need attach/detach semantics for the resolver and the
|
||||||
|
* adb? They can't be used separately, and the references to
|
||||||
|
* them in the view MUST exist until they're both shutdown.
|
||||||
|
* Using create/destroy is probably better. Allow attach/detach
|
||||||
|
* to be done at the view level.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_resolver_detach(dns_resolver_t **resp) {
|
||||||
|
dns_resolver_t *res;
|
||||||
|
isc_boolean_t need_destroy = ISC_FALSE;
|
||||||
|
|
||||||
|
REQUIRE(resp != NULL);
|
||||||
|
res = *resp;
|
||||||
|
REQUIRE(VALID_RESOLVER(res));
|
||||||
|
|
||||||
|
RTRACE("detach");
|
||||||
|
|
||||||
|
LOCK(&res->lock);
|
||||||
|
|
||||||
|
INSIST(res->references > 0);
|
||||||
|
res->references--;
|
||||||
|
if (res->references == 0) {
|
||||||
|
INSIST(res->exiting && res->activebuckets == 0);
|
||||||
|
need_destroy = ISC_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
UNLOCK(&res->lock);
|
UNLOCK(&res->lock);
|
||||||
|
|
||||||
if (need_destroy)
|
if (need_destroy)
|
||||||
@@ -3331,8 +3443,9 @@ void
|
|||||||
dns_resolver_destroyfetch(dns_resolver_t *res, dns_fetch_t **fetchp) {
|
dns_resolver_destroyfetch(dns_resolver_t *res, dns_fetch_t **fetchp) {
|
||||||
dns_fetch_t *fetch;
|
dns_fetch_t *fetch;
|
||||||
dns_fetchevent_t *event, *next_event;
|
dns_fetchevent_t *event, *next_event;
|
||||||
isc_event_t *cevent;
|
|
||||||
fetchctx_t *fctx;
|
fetchctx_t *fctx;
|
||||||
|
unsigned int bucketnum;
|
||||||
|
isc_boolean_t bucket_empty = ISC_FALSE;
|
||||||
|
|
||||||
REQUIRE(fetchp != NULL);
|
REQUIRE(fetchp != NULL);
|
||||||
fetch = *fetchp;
|
fetch = *fetchp;
|
||||||
@@ -3341,11 +3454,12 @@ dns_resolver_destroyfetch(dns_resolver_t *res, dns_fetch_t **fetchp) {
|
|||||||
|
|
||||||
FTRACE("destroyfetch");
|
FTRACE("destroyfetch");
|
||||||
|
|
||||||
LOCK(&res->buckets[fctx->bucketnum].lock);
|
bucketnum = fctx->bucketnum;
|
||||||
|
LOCK(&res->buckets[bucketnum].lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sanity check. The caller should have either gotten its
|
* Sanity check: the caller should have gotten its event before
|
||||||
* fetchevent before trying to destroy the fetch.
|
* trying to destroy the fetch.
|
||||||
*/
|
*/
|
||||||
event = NULL;
|
event = NULL;
|
||||||
if (fctx->state != fetchstate_done) {
|
if (fctx->state != fetchstate_done) {
|
||||||
@@ -3362,25 +3476,26 @@ dns_resolver_destroyfetch(dns_resolver_t *res, dns_fetch_t **fetchp) {
|
|||||||
if (fctx->references == 0) {
|
if (fctx->references == 0) {
|
||||||
/*
|
/*
|
||||||
* No one cares about the result of this fetch anymore.
|
* No one cares about the result of this fetch anymore.
|
||||||
* Shut it down.
|
|
||||||
*/
|
*/
|
||||||
fctx->want_shutdown = ISC_TRUE;
|
if (fctx->pending == 0 && SHUTTINGDOWN(fctx)) {
|
||||||
|
/*
|
||||||
/*
|
* This fctx is already shutdown; we were just
|
||||||
* Unless we're still initializing (in which case the
|
* waiting for the last reference to go away.
|
||||||
* control event is still outstanding), we need to post
|
*/
|
||||||
* the control event to tell the fetch we want it to
|
bucket_empty = fctx_destroy(fctx);
|
||||||
* exit.
|
} else {
|
||||||
*/
|
/*
|
||||||
if (fctx->state != fetchstate_init) {
|
* Initiate shutdown.
|
||||||
cevent = &fctx->control_event;
|
*/
|
||||||
isc_task_send(res->buckets[fctx->bucketnum].task,
|
fctx_shutdown(fctx);
|
||||||
&cevent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNLOCK(&res->buckets[fctx->bucketnum].lock);
|
UNLOCK(&res->buckets[bucketnum].lock);
|
||||||
|
|
||||||
isc_mem_put(res->mctx, fetch, sizeof *fetch);
|
isc_mem_put(res->mctx, fetch, sizeof *fetch);
|
||||||
*fetchp = NULL;
|
*fetchp = NULL;
|
||||||
|
|
||||||
|
if (bucket_empty)
|
||||||
|
empty_bucket(res);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user