Commit 63ca494e authored by Brian Wellington's avatar Brian Wellington
Browse files

Added the isc_refcount_t type, which is a generic locked reference counter,

and make the rbtdb, zone, and view objects use it.
This should reduce contention on other locks, since (in the normal)
implementation, the reference count has its own lock.  In the future, it
should also be possible to implement an isc_refcount_t with atomic operations
instead of mutexes, which should also help performance.
parent bce9e213
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.h,v 1.64 2001/01/12 22:22:17 bwelling Exp $ */
/* $Id: view.h,v 1.65 2001/01/30 02:50:49 bwelling Exp $ */
#ifndef DNS_VIEW_H
#define DNS_VIEW_H 1
......@@ -66,6 +66,7 @@
#include <isc/event.h>
#include <isc/mutex.h>
#include <isc/net.h>
#include <isc/refcount.h>
#include <isc/rwlock.h>
#include <isc/stdtime.h>
......@@ -122,8 +123,10 @@ struct dns_view {
*/
dns_acl_t * matchclients;
/* Locked by themselves. */
isc_refcount_t references;
/* Locked by lock. */
unsigned int references;
unsigned int weakrefs;
unsigned int attributes;
/* Under owner's locking control. */
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rbtdb.c,v 1.145 2001/01/24 02:40:19 halley Exp $ */
/* $Id: rbtdb.c,v 1.146 2001/01/30 02:50:45 bwelling Exp $ */
/*
* Principal Author: Bob Halley
......@@ -24,7 +24,9 @@
#include <config.h>
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <isc/rwlock.h>
#include <isc/string.h>
#include <isc/util.h>
......@@ -157,7 +159,7 @@ typedef struct {
rbtdb_nodelock_t * node_locks;
dns_rbtnode_t * origin_node;
/* Locked by lock. */
unsigned int references;
isc_refcount_t references;
unsigned int attributes;
rbtdb_serial_t current_serial;
rbtdb_serial_t least_serial;
......@@ -316,10 +318,7 @@ attach(dns_db_t *source, dns_db_t **targetp) {
REQUIRE(VALID_RBTDB(rbtdb));
LOCK(&rbtdb->lock);
REQUIRE(rbtdb->references > 0);
rbtdb->references++;
UNLOCK(&rbtdb->lock);
isc_refcount_increment(&rbtdb->references, NULL);
*targetp = source;
}
......@@ -345,6 +344,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb) {
isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks,
rbtdb->node_lock_count * sizeof (rbtdb_nodelock_t));
isc_rwlock_destroy(&rbtdb->tree_lock);
isc_refcount_destroy(&rbtdb->references);
DESTROYLOCK(&rbtdb->lock);
rbtdb->common.magic = 0;
rbtdb->common.impmagic = 0;
......@@ -382,18 +382,13 @@ maybe_free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t set_exiting) {
static void
detach(dns_db_t **dbp) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(*dbp);
isc_boolean_t maybe_free = ISC_FALSE;
unsigned int refs;
REQUIRE(VALID_RBTDB(rbtdb));
LOCK(&rbtdb->lock);
REQUIRE(rbtdb->references > 0);
rbtdb->references--;
if (rbtdb->references == 0)
maybe_free = ISC_TRUE;
UNLOCK(&rbtdb->lock);
isc_refcount_decrement(&rbtdb->references, &refs);
if (maybe_free)
if (refs == 0)
maybe_free_rbtdb(rbtdb, ISC_TRUE);
*dbp = NULL;
......@@ -4093,7 +4088,7 @@ dns_rbtdb_create
/*
* Misc. Initialization.
*/
rbtdb->references = 1;
isc_refcount_init(&rbtdb->references, 1);
rbtdb->attributes = 0;
rbtdb->secure = ISC_FALSE;
rbtdb->overmem = ISC_FALSE;
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.c,v 1.92 2001/01/12 22:22:16 bwelling Exp $ */
/* $Id: view.c,v 1.93 2001/01/30 02:50:46 bwelling Exp $ */
#include <config.h>
......@@ -135,7 +135,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->rdclass = rdclass;
view->frozen = ISC_FALSE;
view->task = NULL;
view->references = 1;
isc_refcount_init(&view->references, 1);
view->weakrefs = 0;
view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
DNS_VIEWATTR_REQSHUTDOWN);
......@@ -217,7 +217,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
static inline void
destroy(dns_view_t *view) {
REQUIRE(!ISC_LINK_LINKED(view, link));
REQUIRE(view->references == 0);
REQUIRE(isc_refcount_current(&view->references) == 0);
REQUIRE(view->weakrefs == 0);
REQUIRE(RESSHUTDOWN(view));
REQUIRE(ADBSHUTDOWN(view));
......@@ -260,6 +260,7 @@ destroy(dns_view_t *view) {
dns_fwdtable_destroy(&view->fwdtable);
isc_rwlock_destroy(&view->conflock);
DESTROYLOCK(&view->lock);
isc_refcount_destroy(&view->references);
isc_mem_free(view->mctx, view->name);
isc_mem_put(view->mctx, view, sizeof *view);
}
......@@ -271,7 +272,8 @@ destroy(dns_view_t *view) {
static isc_boolean_t
all_done(dns_view_t *view) {
if (view->references == 0 && view->weakrefs == 0 &&
if (isc_refcount_current(&view->references) == 0 &&
view->weakrefs == 0 &&
RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
return (ISC_TRUE);
......@@ -284,13 +286,7 @@ dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
REQUIRE(DNS_VIEW_VALID(source));
REQUIRE(targetp != NULL && *targetp == NULL);
LOCK(&source->lock);
INSIST(source->references > 0);
source->references++;
INSIST(source->references != 0);
UNLOCK(&source->lock);
isc_refcount_increment(&source->references, NULL);
*targetp = source;
}
......@@ -298,17 +294,16 @@ dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
static void
view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
dns_view_t *view;
unsigned int refs;
isc_boolean_t done = ISC_FALSE;
REQUIRE(viewp != NULL);
view = *viewp;
REQUIRE(DNS_VIEW_VALID(view));
LOCK(&view->lock);
INSIST(view->references > 0);
view->references--;
if (view->references == 0) {
isc_refcount_decrement(&view->references, &refs);
if (refs == 0) {
LOCK(&view->lock);
if (!RESSHUTDOWN(view))
dns_resolver_shutdown(view->resolver);
if (!ADBSHUTDOWN(view))
......@@ -320,8 +315,8 @@ view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
else
dns_zt_detach(&view->zonetable);
done = all_done(view);
UNLOCK(&view->lock);
}
UNLOCK(&view->lock);
*viewp = NULL;
......
......@@ -15,14 +15,16 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.c,v 1.300 2001/01/25 02:30:21 marka Exp $ */
/* $Id: zone.c,v 1.301 2001/01/30 02:50:48 bwelling Exp $ */
#include <config.h>
#include <isc/file.h>
#include <isc/mutex.h>
#include <isc/print.h>
#include <isc/random.h>
#include <isc/ratelimiter.h>
#include <isc/refcount.h>
#include <isc/serial.h>
#include <isc/string.h>
#include <isc/taskpool.h>
......@@ -127,13 +129,13 @@ struct dns_zone {
isc_boolean_t locked;
#endif
isc_mem_t *mctx;
isc_refcount_t erefs;
/* Locked */
dns_db_t *db;
dns_zonemgr_t *zmgr;
ISC_LINK(dns_zone_t) link; /* Used by zmgr. */
isc_timer_t *timer;
unsigned int erefs;
unsigned int irefs;
dns_name_t origin;
char *masterfile;
......@@ -462,7 +464,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->db = NULL;
zone->zmgr = NULL;
ISC_LINK_INIT(zone, link);
zone->erefs = 1; /* Implicit attach. */
isc_refcount_init(&zone->erefs, 1); /* Implicit attach. */
zone->irefs = 0;
dns_name_init(&zone->origin, NULL);
zone->masterfile = NULL;
......@@ -550,7 +552,7 @@ zone_free(dns_zone_t *zone) {
isc_mem_t *mctx = NULL;
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(zone->erefs == 0);
REQUIRE(isc_refcount_current(&zone->erefs) == 0);
REQUIRE(zone->irefs == 0);
REQUIRE(!LOCKED_ZONE(zone));
......@@ -602,6 +604,7 @@ zone_free(dns_zone_t *zone) {
/* last stuff */
DESTROYLOCK(&zone->lock);
isc_refcount_destroy(&zone->erefs);
zone->magic = 0;
mctx = zone->mctx;
isc_mem_put(mctx, zone, sizeof *zone);
......@@ -1282,7 +1285,7 @@ exit_check(dns_zone_t *zone) {
/*
* DNS_ZONEFLG_SHUTDOWN can only be set if erefs == 0.
*/
INSIST(zone->erefs == 0);
INSIST(isc_refcount_current(&zone->erefs) == 0);
return (ISC_TRUE);
}
return (ISC_FALSE);
......@@ -1436,29 +1439,24 @@ void
dns_zone_attach(dns_zone_t *source, dns_zone_t **target) {
REQUIRE(DNS_ZONE_VALID(source));
REQUIRE(target != NULL && *target == NULL);
LOCK_ZONE(source);
REQUIRE(source->erefs > 0);
source->erefs++;
INSIST(source->erefs != 0);
zone_debuglog(source, "dns_zone_attach", 10,
"eref = %d, irefs = %d", source->erefs, source->irefs);
UNLOCK_ZONE(source);
isc_refcount_increment(&source->erefs, NULL);
*target = source;
}
void
dns_zone_detach(dns_zone_t **zonep) {
dns_zone_t *zone;
unsigned int refs;
isc_boolean_t free_now = ISC_FALSE;
REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
zone = *zonep;
LOCK_ZONE(zone);
REQUIRE(zone->erefs > 0);
zone->erefs--;
if (zone->erefs == 0) {
isc_refcount_decrement(&zone->erefs, &refs);
if (refs == 0) {
LOCK_ZONE(zone);
/*
* We just detached the last external reference.
*/
......@@ -1486,10 +1484,8 @@ dns_zone_detach(dns_zone_t **zonep) {
INSIST(zone->view == NULL);
free_now = ISC_TRUE;
}
UNLOCK_ZONE(zone);
}
zone_debuglog(zone, "dns_zone_detach", 10,
"eref = %d, irefs = %d", zone->erefs, zone->irefs);
UNLOCK_ZONE(zone);
*zonep = NULL;
if (free_now)
zone_free(zone);
......@@ -1516,8 +1512,6 @@ zone_iattach(dns_zone_t *source, dns_zone_t **target) {
source->irefs++;
INSIST(source->irefs != 0);
*target = source;
zone_debuglog(source, "zone_iattach", 10,
"eref = %d, irefs = %d", source->erefs, source->irefs);
}
static void
......@@ -1534,9 +1528,7 @@ zone_idetach(dns_zone_t **zonep) {
INSIST(zone->irefs > 0);
zone->irefs--;
zone_debuglog(zone, "zone_idetach", 10,
"eref = %d, irefs = %d", zone->erefs, zone->irefs);
INSIST(zone->irefs + zone->erefs > 0);
INSIST(zone->irefs + isc_refcount_current(&zone->erefs) > 0);
}
void
......@@ -1551,8 +1543,6 @@ dns_zone_idetach(dns_zone_t **zonep) {
LOCK_ZONE(zone);
INSIST(zone->irefs > 0);
zone->irefs--;
zone_debuglog(zone, "dns_zone_idetach", 10,
"eref = %d, irefs = %d", zone->erefs, zone->irefs);
free_needed = exit_check(zone);
UNLOCK_ZONE(zone);
if (free_needed)
......@@ -3610,7 +3600,7 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
REQUIRE(DNS_ZONE_VALID(zone));
INSIST(event->ev_type == DNS_EVENT_ZONECONTROL);
INSIST(zone->erefs == 0);
INSIST(isc_refcount_current(&zone->erefs) == 0);
zone_debuglog(zone, "zone_shutdown", 3, "shutting down");
/*
......@@ -5640,7 +5630,7 @@ zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
* XXXAG This should be done as soon as the zone goes on the
* queue, using irefs.
*/
zone->erefs++;
isc_refcount_increment(&zone->erefs, NULL);
isc_task_send(zone->task, &e);
UNLOCK_ZONE(zone);
......
#ifndef ISC_REFERENCE_H
#define ISC_REFERENCE_H 1
#include <isc/lang.h>
#include <isc/platform.h>
#include <isc/types.h>
#include <isc/util.h>
/*
* Implements a locked reference counter. These functions may actually be
* implemented using macros, and implementations of these macros are below.
* The isc_refcount_t type should not be accessed directly, as its contents
* depend on the implementation.
*/
ISC_LANG_BEGINDECLS
/*
* Function prototypes
*/
/*
* void
* isc_refcount_init(isc_refcount_t *ref, unsigned int n);
*
* Initialize the reference counter. There will be 'n' initial references.
*
* Requires:
* ref != NULL
*/
/*
* void
* isc_refcount_destroy(isc_refcount_t *ref);
*
* Destroys a reference counter.
*
* Requires:
* ref != NULL
* The number of references is 0.
*/
/*
* void
* isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp);
*
* Increments the reference count, returning the new value in targetp if it's
* not NULL.
*
* Requires:
* ref != NULL.
*/
/*
* void
* isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp);
*
* Decrements the reference count, returning the new value in targetp if it's
* not NULL.
*
* Requires:
* ref != NULL.
*/
/*
* Sample implementations
*/
#ifdef ISC_PLATFORM_USETHREADS
typedef struct isc_refcount {
int refs;
isc_mutex_t lock;
} isc_refcount_t;
#define isc_refcount_init(rp, n) \
do { \
isc_result_t _r; \
(rp)->refs = (n); \
_r = isc_mutex_init(&(rp)->lock); \
RUNTIME_CHECK(_r == ISC_R_SUCCESS); \
} while (0)
#define isc_refcount_destroy(rp) \
do { \
REQUIRE((rp)->refs == 0); \
DESTROYLOCK(&(rp)->lock); \
} while (0)
#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
#define isc_refcount_increment(rp, tp) \
do { \
LOCK(&(rp)->lock); \
REQUIRE((rp)->refs > 0); \
++((rp)->refs); \
if ((tp) != NULL) \
*(unsigned int *)(tp) = ((rp)->refs); \
UNLOCK(&(rp)->lock); \
} while (0)
#define isc_refcount_decrement(rp, tp) \
do { \
LOCK(&(rp)->lock); \
REQUIRE((rp)->refs > 0); \
--((rp)->refs); \
if ((tp) != NULL) \
*(unsigned int *)(tp) = ((rp)->refs); \
UNLOCK(&(rp)->lock); \
} while (0)
#else
typedef struct isc_refcount {
int refs;
} isc_refcount_t;
#define isc_refcount_init(rp, n) ((rp)->refs = (n))
#define isc_refcount_destroy(rp) (REQUIRE((rp)->refs == 0))
#define isc_refcount_current(rp) ((unsigned int)((rp)->refs))
#define isc_refcount_increment(rp, tp) \
do { \
int _n = ++(rp)->refs; \
if ((tp) != NULL) \
*(unsigned int *)(tp) = (unsigned int)(_n); \
} while (0)
#define isc_refcount_decrement(rp, tp) \
do { \
int _n = --(rp)->refs; \
if ((tp) != NULL) \
*(unsigned int *)(tp) = (unsigned int)(_n); \
} while (0)
#endif
ISC_LANG_ENDDECLS
#endif /* ISC_REFCOUNT_H */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment