diff --git a/CHANGES b/CHANGES index 8b72400507..6b95740f91 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +1461. [bug] Remove deadlock from rbtdb code. [RT #5999] + 1460. [bug] inet_pton() failed to reject certian malformed IPv6 literals. diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 4ec6a9e185..267f5cc2bc 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.186 2003/02/27 00:19:03 marka Exp $ */ +/* $Id: rbtdb.c,v 1.187 2003/04/17 01:56:34 marka Exp $ */ /* * Principal Author: Bob Halley @@ -815,10 +815,10 @@ no_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, * we only do a trylock. */ if (lock == isc_rwlocktype_read) - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); - - result = isc_rwlock_trylock(&rbtdb->tree_lock, - isc_rwlocktype_write); + result = isc_rwlock_tryupgrade(&rbtdb->tree_lock); + else + result = isc_rwlock_trylock(&rbtdb->tree_lock, + isc_rwlocktype_write); RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_LOCKBUSY); @@ -849,12 +849,13 @@ no_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, /* * Relock a read lock, or unlock the write lock if no lock was held. */ - if (lock != isc_rwlocktype_write) + if (lock == isc_rwlocktype_none) if (write_locked) RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); if (lock == isc_rwlocktype_read) - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + if (write_locked) + isc_rwlock_downgrade(&rbtdb->tree_lock); } static inline void diff --git a/lib/isc/include/isc/rwlock.h b/lib/isc/include/isc/rwlock.h index 0313c050c2..d84d4db210 100644 --- a/lib/isc/include/isc/rwlock.h +++ b/lib/isc/include/isc/rwlock.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rwlock.h,v 1.18 2001/03/08 00:55:15 tale Exp $ */ +/* $Id: rwlock.h,v 1.19 2003/04/17 01:56:35 marka Exp $ */ #ifndef ISC_RWLOCK_H #define ISC_RWLOCK_H 1 @@ -80,6 +80,12 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type); isc_result_t isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type); +isc_result_t +isc_rwlock_tryupgrade(isc_rwlock_t *rwl); + +void +isc_rwlock_downgrade(isc_rwlock_t *rwl); + void isc_rwlock_destroy(isc_rwlock_t *rwl); diff --git a/lib/isc/rwlock.c b/lib/isc/rwlock.c index 6ddcbdba6b..25172dcdd3 100644 --- a/lib/isc/rwlock.c +++ b/lib/isc/rwlock.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rwlock.c,v 1.33 2001/04/17 14:36:45 tale Exp $ */ +/* $Id: rwlock.c,v 1.34 2003/04/17 01:56:34 marka Exp $ */ #include @@ -205,6 +205,44 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { return (doit(rwl, type, ISC_TRUE)); } +isc_result_t +isc_rwlock_tryupgrade(isc_rwlock_t *rwl) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(VALID_RWLOCK(rwl)); + LOCK(&rwl->lock); + REQUIRE(rwl->type == isc_rwlocktype_read); + REQUIRE(rwl->active != 0); + + /* If we are the only reader then succeed. */ + if (rwl->active == 1) + rwl->type = isc_rwlocktype_write; + else + result = ISC_R_LOCKBUSY; + + UNLOCK(&rwl->lock); + return (result); +} + +void +isc_rwlock_downgrade(isc_rwlock_t *rwl) { + + REQUIRE(VALID_RWLOCK(rwl)); + LOCK(&rwl->lock); + REQUIRE(rwl->type == isc_rwlocktype_write); + REQUIRE(rwl->active == 1); + + rwl->type = isc_rwlocktype_read; + /* + * Wake up waiting readers if there are no waiting writers. + */ + if ((rwl->writers_waiting == 0 || rwl->granted < rwl->read_quota) && + rwl->readers_waiting > 0) + BROADCAST(&rwl->readable); + + UNLOCK(&rwl->lock); +} + isc_result_t isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { @@ -318,6 +356,32 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { return (isc_rwlock_lock(rwl, type)); } +isc_result_t +isc_rwlock_tryupgrade(isc_rwlock_t *rwl) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(VALID_RWLOCK(rwl)); + REQUIRE(rwl->type == isc_rwlocktype_read); + REQUIRE(rwl->active != 0); + + /* If we are the only reader then succeed. */ + if (rwl->active == 1) + rwl->type = isc_rwlocktype_write; + else + result = ISC_R_LOCKBUSY; + return (result); +} + +void +isc_rwlock_downgrade(isc_rwlock_t *rwl) { + + REQUIRE(VALID_RWLOCK(rwl)); + REQUIRE(rwl->type == isc_rwlocktype_write); + REQUIRE(rwl->active == 1); + + rwl->type = isc_rwlocktype_read; +} + isc_result_t isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { REQUIRE(VALID_RWLOCK(rwl));