From: Ondřej Surý Date: Thu, 22 Nov 2018 10:42:12 +0000 (+0100) Subject: Implement isc_rwlock_downgrade using pthreads and single atomic_bool X-Git-Tag: v9.15.1~25^2~1 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=4501f646eecd49bda19862187d4f550218bdaf8f;p=thirdparty%2Fbind9.git Implement isc_rwlock_downgrade using pthreads and single atomic_bool --- diff --git a/lib/isc/include/isc/rwlock.h b/lib/isc/include/isc/rwlock.h index 50d06d72d00..5551c1b6239 100644 --- a/lib/isc/include/isc/rwlock.h +++ b/lib/isc/include/isc/rwlock.h @@ -36,6 +36,7 @@ typedef enum { struct isc_rwlock { pthread_rwlock_t rwlock; + atomic_bool downgrade; }; #else /* HAVE_PTHREAD_RWLOCK_RDLOCK */ diff --git a/lib/isc/rwlock.c b/lib/isc/rwlock.c index 2619619d1b4..7d5e14ea4eb 100644 --- a/lib/isc/rwlock.c +++ b/lib/isc/rwlock.c @@ -39,15 +39,32 @@ isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota, 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_release(&rwl->downgrade)) { + REQUIRE(pthread_rwlock_unlock(&rwl->rwlock) + == 0); + while (atomic_load(&rwl->downgrade)); + continue; + } + break; + } + break; + default: + INSIST(0); + ISC_UNREACHABLE(); } return (ISC_R_SUCCESS); } @@ -61,6 +78,10 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { 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); } @@ -88,8 +109,10 @@ isc_rwlock_tryupgrade(isc_rwlock_t *rwl) { void isc_rwlock_downgrade(isc_rwlock_t *rwl) { + atomic_store_acquire(&rwl->downgrade, true); isc_rwlock_unlock(rwl, isc_rwlocktype_write); isc_rwlock_lock(rwl, isc_rwlocktype_read); + atomic_store_acquire(&rwl->downgrade, false); } void