summaryrefslogtreecommitdiff
path: root/lib/isc/rwlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/isc/rwlock.c')
-rw-r--r--lib/isc/rwlock.c80
1 files changed, 78 insertions, 2 deletions
diff --git a/lib/isc/rwlock.c b/lib/isc/rwlock.c
index 6ddcbdba..c31b2a11 100644
--- a/lib/isc/rwlock.c
+++ b/lib/isc/rwlock.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1998-2001 Internet Software Consortium.
+ * Copyright (C) 1998-2001, 2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -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.33.2.4 2003/07/23 03:20:24 marka Exp $ */
#include <config.h>
@@ -82,6 +82,7 @@ isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
rwl->magic = 0;
rwl->type = isc_rwlocktype_read;
+ rwl->original = isc_rwlocktype_none;
rwl->active = 0;
rwl->granted = 0;
rwl->readers_waiting = 0;
@@ -206,6 +207,50 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
}
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->original = (rwl->original == isc_rwlocktype_none) ?
+ isc_rwlocktype_read : isc_rwlocktype_none;
+ 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;
+ rwl->original = (rwl->original == isc_rwlocktype_none) ?
+ isc_rwlocktype_write : isc_rwlocktype_none;
+ /*
+ * Resume processing any read request that were blocked when
+ * we upgraded.
+ */
+ if (rwl->original == isc_rwlocktype_none &&
+ (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) {
REQUIRE(VALID_RWLOCK(rwl));
@@ -222,6 +267,10 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
INSIST(rwl->active > 0);
rwl->active--;
if (rwl->active == 0) {
+ if (rwl->original != isc_rwlocktype_none) {
+ rwl->type = rwl->original;
+ rwl->original = isc_rwlocktype_none;
+ }
if (rwl->type == isc_rwlocktype_read) {
rwl->granted = 0;
if (rwl->writers_waiting > 0) {
@@ -249,6 +298,7 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
}
}
}
+ INSIST(rwl->original == isc_rwlocktype_none);
#ifdef ISC_RWLOCK_TRACE
print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
@@ -319,6 +369,32 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t 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));
REQUIRE(rwl->type == type);