diff --git a/config.h.in b/config.h.in index 4f40e31458..817fd003e5 100644 --- a/config.h.in +++ b/config.h.in @@ -309,6 +309,9 @@ /* Have PTHREAD_PRIO_INHERIT. */ #undef HAVE_PTHREAD_PRIO_INHERIT +/* Define to 1 if you have the `pthread_rwlock_rdlock' function. */ +#undef HAVE_PTHREAD_RWLOCK_RDLOCK + /* Define to 1 if you have the `pthread_setaffinity_np' function. */ #undef HAVE_PTHREAD_SETAFFINITY_NP @@ -553,6 +556,9 @@ /* define if PKCS11 is used for Public-Key Cryptography */ #undef USE_PKCS11 +/* Define if you want to use pthread rwlock implementation */ +#undef USE_PTHREAD_RWLOCK + /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE diff --git a/configure b/configure index 09167c62f4..425bb6a44c 100755 --- a/configure +++ b/configure @@ -900,6 +900,7 @@ enable_devpoll with_geoip with_locktype with_libtool +enable_pthread_rwlock with_openssl enable_fips_mode with_cc_alg @@ -1599,6 +1600,8 @@ Optional Features: --enable-kqueue use BSD kqueue when available [default=yes] --enable-epoll use Linux epoll when available [default=auto] --enable-devpoll use /dev/poll when available [default=yes] + --enable-pthread-rwlock use pthread rwlock instead of internal rwlock + implementation (EXPERIMENTAL) --enable-fips-mode enable FIPS mode in OpenSSL library [default=no] --enable-native-pkcs11 use native PKCS11 for public-key crypto [default=no] --enable-backtrace log stack backtrace on abort [default=yes] @@ -15616,10 +15619,34 @@ esac # -# If PIC is disabled, shared libraries must also be +# Do we want to use pthread rwlock? (useful for ThreadSanitizer) # -if test "$pic_mode" = "no"; then : - enable_shared="no" +# Check whether --enable-pthread_rwlock was given. +if test "${enable_pthread_rwlock+set}" = set; then : + enableval=$enable_pthread_rwlock; +else + enable_pthread_rwlock=no +fi + + +if test "$enable_pthread_rwlock" = "yes"; then : + for ac_func in pthread_rwlock_rdlock +do : + ac_fn_c_check_func "$LINENO" "pthread_rwlock_rdlock" "ac_cv_func_pthread_rwlock_rdlock" +if test "x$ac_cv_func_pthread_rwlock_rdlock" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PTHREAD_RWLOCK_RDLOCK 1 +_ACEOF + +else + as_fn_error $? "pthread_rwlock_rdlock requested but not found" "$LINENO" 5 +fi +done + + +$as_echo "#define USE_PTHREAD_RWLOCK 1" >>confdefs.h + + fi CRYPTO=OpenSSL diff --git a/configure.ac b/configure.ac index 1e20f1724e..7064846004 100644 --- a/configure.ac +++ b/configure.ac @@ -734,10 +734,18 @@ esac AC_SUBST(INSTALL_LIBRARY) # -# If PIC is disabled, shared libraries must also be +# Do we want to use pthread rwlock? (useful for ThreadSanitizer) # -AS_IF([test "$pic_mode" = "no"], - [enable_shared="no"]) +AC_ARG_ENABLE([pthread_rwlock], + [AS_HELP_STRING([--enable-pthread-rwlock], + [use pthread rwlock instead of internal rwlock implementation (EXPERIMENTAL)])], + [], [enable_pthread_rwlock=no]) + +AS_IF([test "$enable_pthread_rwlock" = "yes"], + [AC_CHECK_FUNCS([pthread_rwlock_rdlock], [], + [AC_MSG_ERROR([pthread_rwlock_rdlock requested but not found])]) + AC_DEFINE([USE_PTHREAD_RWLOCK],[1],[Define if you want to use pthread rwlock implementation]) + ]) CRYPTO=OpenSSL diff --git a/lib/isc/include/isc/rwlock.h b/lib/isc/include/isc/rwlock.h index ed1ff66312..d1a4545339 100644 --- a/lib/isc/include/isc/rwlock.h +++ b/lib/isc/include/isc/rwlock.h @@ -14,6 +14,7 @@ #define ISC_RWLOCK_H 1 #include +#include /*! \file isc/rwlock.h */ @@ -31,6 +32,15 @@ typedef enum { isc_rwlocktype_write } isc_rwlocktype_t; +#if USE_PTHREAD_RWLOCK + +struct isc_rwlock { + pthread_rwlock_t rwlock; + atomic_bool downgrade; +}; + +#else /* USE_PTHREAD_RWLOCK */ + struct isc_rwlock { /* Unlocked. */ unsigned int magic; @@ -68,6 +78,8 @@ struct isc_rwlock { }; +#endif /* USE_PTHREAD_RWLOCK */ + isc_result_t isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota, unsigned int write_quota); diff --git a/lib/isc/rwlock.c b/lib/isc/rwlock.c index 1071fecc07..d756d663ab 100644 --- a/lib/isc/rwlock.c +++ b/lib/isc/rwlock.c @@ -27,6 +27,101 @@ #include #include +#if USE_PTHREAD_RWLOCK + +#include +#include + +isc_result_t +isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota, + unsigned int write_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: + 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); +} + +isc_result_t +isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + int ret = 0; + switch (type) { + case isc_rwlocktype_read: + ret = pthread_rwlock_tryrdlock(&rwl->rwlock); + 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); + } + + switch (ret) { + case 0: return (ISC_R_SUCCESS); + case EBUSY: return (ISC_R_LOCKBUSY); + case EAGAIN: return (ISC_R_LOCKBUSY); + default: INSIST(0); ISC_UNREACHABLE(); + } +} + + +isc_result_t +isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + UNUSED(type); + REQUIRE(pthread_rwlock_unlock(&rwl->rwlock) == 0); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_rwlock_tryupgrade(isc_rwlock_t *rwl) { + return (ISC_R_LOCKBUSY); +} + +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 +isc_rwlock_destroy(isc_rwlock_t *rwl) { + pthread_rwlock_destroy(&rwl->rwlock); +} + +#else + #define RWLOCK_MAGIC ISC_MAGIC('R', 'W', 'L', 'k') #define VALID_RWLOCK(rwl) ISC_MAGIC_VALID(rwl, RWLOCK_MAGIC) @@ -549,3 +644,5 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { return (ISC_R_SUCCESS); } + +#endif /* USE_PTHREAD_RWLOCK */