]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1461. [bug] Remove deadlock from rbtdb code. [RT #5999]
authorMark Andrews <marka@isc.org>
Thu, 17 Apr 2003 01:56:35 +0000 (01:56 +0000)
committerMark Andrews <marka@isc.org>
Thu, 17 Apr 2003 01:56:35 +0000 (01:56 +0000)
CHANGES
lib/dns/rbtdb.c
lib/isc/include/isc/rwlock.h
lib/isc/rwlock.c

diff --git a/CHANGES b/CHANGES
index 8b72400507172b996d625e9f26c8c38338b1abaf..6b95740f919e0f18b14282f82d333f455bbb6530 100644 (file)
--- 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.
 
index 4ec6a9e185b7afaf4b84260a1980e69647d362b8..267f5cc2bc4afc361c86d9fcb8ab94b12a417035 100644 (file)
@@ -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
index 0313c050c2a083ab2a1cd6bb2d75cd006e70a035..d84d4db2102e4fa1387ed7917f9d1cf21def612d 100644 (file)
@@ -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);
 
index 6ddcbdba6b633fe33cea68abcb0974aade1661e1..25172dcdd3692ce06639a31018e4d963ca856069 100644 (file)
@@ -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 <config.h>
 
@@ -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));