UNUSED(read_quota);
UNUSED(write_quota);
REQUIRE(pthread_rwlock_init(&rwl->rwlock, NULL) == 0);
+ atomic_init(&rwl->downgrade, false);
return (ISC_R_SUCCESS);
}
isc_result_t
isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
switch (type) {
- case isc_rwlocktype_read: REQUIRE(pthread_rwlock_rdlock(&rwl->rwlock) == 0); break;
- case isc_rwlocktype_write: REQUIRE(pthread_rwlock_wrlock(&rwl->rwlock) == 0); break;
- default: INSIST(0);
+ case isc_rwlocktype_read:
+ REQUIRE(pthread_rwlock_rdlock(&rwl->rwlock) == 0);
+ break;
+ case isc_rwlocktype_write:
+ while (true) {
+ REQUIRE(pthread_rwlock_wrlock(&rwl->rwlock) == 0);
+ /* Unlock if in middle of downgrade operation */
+ if (atomic_load(&rwl->downgrade)) {
+ isc_rwlock_unlock(rwl, type);
+ while (atomic_load(&rwl->downgrade));
+ continue;
+ }
+ break;
+ }
+ break;
+ default:
+ INSIST(0);
+ ISC_UNREACHABLE();
}
return (ISC_R_SUCCESS);
}
break;
case isc_rwlocktype_write:
ret = pthread_rwlock_trywrlock(&rwl->rwlock);
+ if ((ret == 0) && atomic_load(&rwl->downgrade)) {
+ isc_rwlock_unlock(rwl, type);
+ return (ISC_R_LOCKBUSY);
+ }
break;
default: INSIST(0);
}
void
isc_rwlock_downgrade(isc_rwlock_t *rwl) {
+ atomic_store(&rwl->downgrade, true);
isc_rwlock_unlock(rwl, isc_rwlocktype_write);
isc_rwlock_lock(rwl, isc_rwlocktype_read);
+ atomic_store(&rwl->downgrade, false);
}
void