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.
* 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
#include <isc/event.h>
#include <isc/mutex.h>
#include <isc/net.h>
+#include <isc/refcount.h>
#include <isc/rwlock.h>
#include <isc/stdtime.h>
*/
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. */
* 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
#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>
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;
REQUIRE(VALID_RBTDB(rbtdb));
- LOCK(&rbtdb->lock);
- REQUIRE(rbtdb->references > 0);
- rbtdb->references++;
- UNLOCK(&rbtdb->lock);
+ isc_refcount_increment(&rbtdb->references, NULL);
*targetp = source;
}
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;
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;
/*
* Misc. Initialization.
*/
- rbtdb->references = 1;
+ isc_refcount_init(&rbtdb->references, 1);
rbtdb->attributes = 0;
rbtdb->secure = ISC_FALSE;
rbtdb->overmem = ISC_FALSE;
* 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>
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);
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));
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);
}
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);
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;
}
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))
else
dns_zt_detach(&view->zonetable);
done = all_done(view);
+ UNLOCK(&view->lock);
}
- UNLOCK(&view->lock);
*viewp = NULL;
* 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>
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;
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;
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));
/* last stuff */
DESTROYLOCK(&zone->lock);
+ isc_refcount_destroy(&zone->erefs);
zone->magic = 0;
mctx = zone->mctx;
isc_mem_put(mctx, zone, sizeof *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);
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.
*/
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);
source->irefs++;
INSIST(source->irefs != 0);
*target = source;
- zone_debuglog(source, "zone_iattach", 10,
- "eref = %d, irefs = %d", source->erefs, source->irefs);
}
static void
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
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)
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");
/*
* 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);
--- /dev/null
+#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 */