isc_mem_t * mctx;
isc_stdtime_t now;
+ /* Atomic */
+ isc_refcount_t references;
+
+
/*% Locked by appropriate bucket lock. */
fetchstate state;
- bool want_shutdown;
- bool cloned;
- bool spilled;
- unsigned int references;
+ bool want_shutdown;
+ bool cloned;
+ bool spilled;
isc_event_t control_event;
ISC_LINK(struct fetchctx) link;
ISC_LIST(dns_fetchevent_t) events;
isc_task_t * task;
isc_mutex_t lock;
ISC_LIST(fetchctx_t) fctxs;
- bool exiting;
+ atomic_bool exiting;
isc_mem_t * mctx;
} fctxbucket_t;
unsigned int magic;
isc_mem_t * mctx;
isc_mutex_t lock;
- isc_mutex_t nlock;
isc_mutex_t primelock;
dns_rdataclass_t rdclass;
isc_socketmgr_t * socketmgr;
unsigned int retryinterval; /* in milliseconds */
unsigned int nonbackofftries;
+ /* Atomic */
+ isc_refcount_t references;
+ atomic_bool exiting;
+
/* Locked by lock. */
- unsigned int references;
- bool exiting;
isc_eventlist_t whenshutdown;
unsigned int activebuckets;
- bool priming;
+ bool priming;
unsigned int spillat; /* clients-per-query */
unsigned int zspill; /* fetches-per-zone */
/* Locked by primelock. */
dns_fetch_t * primefetch;
- /* Locked by nlock. */
- unsigned int nfctx;
+
+ /* Atomic. */
+ isc_refcount_t nfctx;
};
#define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!')
fctx->spilled &&
(count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) {
LOCK(&fctx->res->lock);
- if (count == fctx->res->spillat && !fctx->res->exiting) {
+ if (count == fctx->res->spillat &&
+ !atomic_load_acquire(&fctx->res->exiting)) {
old_spillat = fctx->res->spillat;
fctx->res->spillat += 5;
if (fctx->res->spillat > fctx->res->spillatmax &&
} else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
- if (fctx->references == 0) {
+ if (isc_refcount_current(&fctx->references) == 0) {
bucket_empty = fctx_unlink(fctx);
dodestroy = true;
}
REQUIRE(ISC_LIST_EMPTY(fctx->finds));
REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
REQUIRE(fctx->pending == 0);
- REQUIRE(fctx->references == 0);
REQUIRE(ISC_LIST_EMPTY(fctx->validators));
FCTXTRACE("unlink");
+ isc_refcount_destroy(&fctx->references);
+
res = fctx->res;
bucketnum = fctx->bucketnum;
ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
- LOCK(&res->nlock);
- res->nfctx--;
- UNLOCK(&res->nlock);
+ isc_refcount_decrement(&res->nfctx);
+
dec_stats(res, dns_resstatscounter_nfetch);
- if (res->buckets[bucketnum].exiting &&
+ if (atomic_load_acquire(&res->buckets[bucketnum].exiting) &&
ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
+ {
return (true);
+ }
return (false);
}
REQUIRE(ISC_LIST_EMPTY(fctx->finds));
REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
REQUIRE(fctx->pending == 0);
- REQUIRE(fctx->references == 0);
REQUIRE(ISC_LIST_EMPTY(fctx->validators));
REQUIRE(!ISC_LINK_LINKED(fctx, link));
FCTXTRACE("destroy");
+ isc_refcount_destroy(&fctx->references);
+
/*
* Free bad.
*/
fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__);
}
- if (fctx->references == 0 && fctx->pending == 0 &&
- fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
+ if (isc_refcount_current(&fctx->references) == 0 &&
+ fctx->pending == 0 &&
+ fctx->nqueries == 0 &&
+ ISC_LIST_EMPTY(fctx->validators))
+ {
bucket_empty = fctx_unlink(fctx);
dodestroy = true;
}
INSIST(fctx->pending == 0);
INSIST(fctx->nqueries == 0);
INSIST(ISC_LIST_EMPTY(fctx->validators));
- if (fctx->references == 0) {
+ if (isc_refcount_current(&fctx->references) == 0) {
/*
* It's now safe to destroy this fctx.
*/
ISC_LIST_PREPEND(fctx->events, event, ev_link);
else
ISC_LIST_APPEND(fctx->events, event, ev_link);
- fctx->references++;
+
+ fctx_increference(fctx);
+
fctx->client = client;
fetch->magic = DNS_FETCH_MAGIC;
* using it.
*/
fctx->res = res;
- fctx->references = 0;
+ isc_refcount_init(&fctx->references, 0);
fctx->bucketnum = bucketnum;
fctx->dbucketnum = RES_NOBUCKET;
fctx->state = fetchstate_init;
ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
- LOCK(&res->nlock);
- res->nfctx++;
- UNLOCK(&res->nlock);
+ isc_refcount_increment(&res->nfctx);
+
inc_stats(res, dns_resstatscounter_nfetch);
*fctxp = fctx;
dns_validator_cancel(validator);
}
- if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators)) {
+ if (isc_refcount_current(&fctx->references) == 0 &&
+ ISC_LIST_EMPTY(fctx->validators))
+ {
bucket_empty = fctx_unlink(fctx);
dodestroy = true;
}
fctx_increference(fetchctx_t *fctx) {
REQUIRE(VALID_FCTX(fctx));
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
- fctx->references++;
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ isc_refcount_increment(&fctx->references);
}
static bool
REQUIRE(VALID_FCTX(fctx));
- INSIST(fctx->references > 0);
- fctx->references--;
- if (fctx->references == 0) {
+ if (isc_refcount_decrement(&fctx->references) == 1) {
/*
* No one cares about the result of this fetch anymore.
*/
fetchctx_t *fctx;
isc_result_t result;
bool bucket_empty;
- bool locked = false;
- unsigned int bucketnum;
dns_rdataset_t nameservers;
dns_fixedname_t fixed;
dns_name_t *domain;
dns_rdataset_init(&nameservers);
- bucketnum = fctx->bucketnum;
-
/*
* Note: fevent->rdataset must be disassociated and
* isc_event_free(&event) be called before resuming
}
fctx_done(fctx, result, __LINE__);
} else {
- LOCK(&res->buckets[bucketnum].lock);
- locked = true;
- fctx->references++;
+ fctx_increference(fctx);
}
}
cleanup:
INSIST(event == NULL);
INSIST(fevent == NULL);
- if (dns_rdataset_isassociated(&nameservers))
+ if (dns_rdataset_isassociated(&nameservers)) {
dns_rdataset_disassociate(&nameservers);
- if (!locked)
- LOCK(&res->buckets[bucketnum].lock);
+ }
bucket_empty = fctx_decreference(fctx);
- UNLOCK(&res->buckets[bucketnum].lock);
- if (bucket_empty)
+ if (bucket_empty) {
empty_bucket(res);
+ }
}
static inline void
rctx_respinit(task, devent, query, fctx, &rctx);
- if (fctx->res->exiting) {
+ if (atomic_load_acquire(&fctx->res->exiting)) {
result = ISC_R_SHUTTINGDOWN;
FCTXTRACE("resolver shutting down");
rctx_done(&rctx, result);
}
fctx_done(fctx, result, __LINE__);
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
bucket_empty = fctx_decreference(fctx);
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
if (bucket_empty) {
empty_bucket(fctx->res);
}
RTRACE("destroy");
- INSIST(res->nfctx == 0);
+ isc_refcount_destroy(&res->nfctx);
isc_mutex_destroy(&res->primelock);
- isc_mutex_destroy(&res->nlock);
isc_mutex_destroy(&res->lock);
for (i = 0; i < res->nbuckets; i++) {
INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs));
UNUSED(task);
LOCK(&res->lock);
- INSIST(!res->exiting);
+ INSIST(!atomic_load_acquire(&res->exiting));
if (res->spillat > res->spillatmin) {
res->spillat--;
logit = true;
isc_mem_setname(res->buckets[i].mctx, name, NULL);
isc_task_setname(res->buckets[i].task, name, res);
ISC_LIST_INIT(res->buckets[i].fctxs);
- res->buckets[i].exiting = false;
+ atomic_store_release(&res->buckets[i].exiting, false);
buckets_created++;
}
res->querydscp4 = -1;
res->querydscp6 = -1;
- res->references = 1;
- res->exiting = false;
+ isc_refcount_init(&res->references, 1);
+ atomic_init(&res->exiting, false);
res->frozen = false;
ISC_LIST_INIT(res->whenshutdown);
res->priming = false;
res->primefetch = NULL;
- res->nfctx = 0;
+
+ isc_refcount_init(&res->nfctx, 0);
isc_mutex_init(&res->lock);
- isc_mutex_init(&res->nlock);
isc_mutex_init(&res->primelock);
task = NULL;
cleanup_primelock:
isc_mutex_destroy(&res->primelock);
- isc_mutex_destroy(&res->nlock);
isc_mutex_destroy(&res->lock);
if (res->dispatches6 != NULL)
LOCK(&res->lock);
- if (!res->exiting && !res->priming) {
+ /* XXXOND: cas needs to be used here */
+ if (!atomic_load_acquire(&res->exiting) && !res->priming) {
INSIST(res->primefetch == NULL);
res->priming = true;
want_priming = true;
REQUIRE(targetp != NULL && *targetp == NULL);
RRTRACE(source, "attach");
- LOCK(&source->lock);
- REQUIRE(!source->exiting);
- INSIST(source->references > 0);
- source->references++;
- INSIST(source->references != 0);
- UNLOCK(&source->lock);
+ REQUIRE(!atomic_load_acquire(&source->exiting));
+ isc_refcount_increment(&source->references);
*targetp = source;
}
LOCK(&res->lock);
- if (res->exiting && res->activebuckets == 0) {
+ if (atomic_load_acquire(&res->exiting) && res->activebuckets == 0) {
/*
* We're already shutdown. Send the event.
*/
unsigned int i;
fetchctx_t *fctx;
isc_result_t result;
+ bool is_false = false;
REQUIRE(VALID_RESOLVER(res));
RTRACE("shutdown");
- LOCK(&res->lock);
-
- if (!res->exiting) {
+ if (atomic_compare_exchange_strong(&res->exiting, &is_false, true)) {
RTRACE("exiting");
- res->exiting = true;
for (i = 0; i < res->nbuckets; i++) {
LOCK(&res->buckets[i].lock);
NULL, true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
-
- UNLOCK(&res->lock);
}
void
dns_resolver_detach(dns_resolver_t **resp) {
dns_resolver_t *res;
- bool need_destroy = false;
REQUIRE(resp != NULL);
res = *resp;
RTRACE("detach");
- LOCK(&res->lock);
-
- INSIST(res->references > 0);
- res->references--;
- if (res->references == 0) {
- INSIST(res->exiting && res->activebuckets == 0);
- need_destroy = true;
- }
-
- UNLOCK(&res->lock);
+ *resp = NULL;
- if (need_destroy)
+ if (isc_refcount_decrement(&res->references) == 1) {
+ INSIST(atomic_load_acquire(&res->exiting));
+ INSIST(res->activebuckets == 0);
destroy(res);
-
- *resp = NULL;
+ }
}
static inline bool
RUNTIME_CHECK(event->fetch != fetch);
}
}
+ UNLOCK(&res->buckets[bucketnum].lock);
bucket_empty = fctx_decreference(fctx);
- UNLOCK(&res->buckets[bucketnum].lock);
-
isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch));
*fetchp = NULL;
unsigned int
dns_resolver_nrunning(dns_resolver_t *resolver) {
- unsigned int n;
- LOCK(&resolver->nlock);
- n = resolver->nfctx;
- UNLOCK(&resolver->nlock);
- return (n);
+ return (isc_refcount_current(&resolver->nfctx));
}
isc_result_t