From: Brian Wellington Date: Tue, 30 Jan 2001 02:50:51 +0000 (+0000) Subject: Added the isc_refcount_t type, which is a generic locked reference counter, X-Git-Tag: v9.1.1rc1~29^2 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=63ca494e7e9aba8dc6740443fdab69620c7a7523;p=thirdparty%2Fbind9.git 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. --- diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 0fe1bdf09f2..1461bfbb3af 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -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 #include #include +#include #include #include @@ -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. */ diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index fee04e67e5b..58501e0f3d6 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -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 #include +#include #include +#include #include #include #include @@ -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; diff --git a/lib/dns/view.c b/lib/dns/view.c index f485b831931..ef8fd2af1cb 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -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 @@ -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; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 579ae331570..aae98278ab6 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -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 #include +#include #include #include #include +#include #include #include #include @@ -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); diff --git a/lib/isc/include/isc/refcount.h b/lib/isc/include/isc/refcount.h new file mode 100644 index 00000000000..20aeb197a40 --- /dev/null +++ b/lib/isc/include/isc/refcount.h @@ -0,0 +1,140 @@ +#ifndef ISC_REFERENCE_H +#define ISC_REFERENCE_H 1 + +#include +#include +#include +#include + +/* + * 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 */