2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

Enable tracking of pthreads rwlocks

Some POSIX threads implementations (e.g. FreeBSD's libthr) allocate
memory on the heap when pthread_rwlock_init() is called.  Every call to
that function must be accompanied by a corresponding call to
pthread_rwlock_destroy() or else the memory allocated for the rwlock
will leak.

jemalloc can be used for detecting memory allocations which are not
released by a process when it exits.  Unfortunately, since jemalloc is
also the system allocator on FreeBSD and a special (profiling-enabled)
build of jemalloc is required for memory leak detection, this method
cannot be used for detecting leaked memory allocated by libthr on a
stock FreeBSD installation.

However, libthr's behavior can be emulated on any platform by
implementing alternative versions of libisc functions for creating and
destroying rwlocks that allocate memory using malloc() and release it
using free().  This enables using jemalloc for detecting missing
pthread_rwlock_destroy() calls on any platform on which it works
reliably.

When the newly introduced ISC_TRACK_PTHREADS_OBJECTS preprocessor macro
is set (and --enable-pthread-rwlock is used), allocate isc_rwlock_t
structures on the heap in isc_rwlock_init() and free them in
isc_rwlock_destroy().  Reuse existing functions defined in
lib/isc/rwlock.c for other operations, but rename them first, so that
they contain triple underscores (to indicate that these functions are
implementation-specific, unlike their mutex and condition variable
counterparts, which always use the pthreads implementation).  Define the
isc__rwlock_init() macro so that it is a logical counterpart of
isc__mutex_init() and isc__condition_init(); adjust isc___rwlock_init()
accordingly.  Remove a redundant function prototype for
isc__rwlock_lock() and rename that (static) function to rwlock_lock() in
order to avoid having to use quadruple underscores.
This commit is contained in:
Ondřej Surý
2022-07-13 13:19:32 +02:00
committed by Michał Kępień
parent 8dfdb95a20
commit e4606da2c6
3 changed files with 89 additions and 35 deletions

View File

@@ -14,6 +14,7 @@
#pragma once
#include <inttypes.h>
#include <stdlib.h>
/*! \file isc/rwlock.h */
@@ -21,6 +22,7 @@
#include <isc/condition.h>
#include <isc/lang.h>
#include <isc/types.h>
#include <isc/util.h>
ISC_LANG_BEGINDECLS
@@ -38,6 +40,42 @@ struct isc_rwlock {
atomic_bool downgrade;
};
#if ISC_TRACK_PTHREADS_OBJECTS
typedef struct isc_rwlock *isc_rwlock_t;
typedef struct isc_rwlock isc__rwlock_t;
#define isc_rwlock_init(rwl, rq, wq) \
{ \
*rwl = malloc(sizeof(**rwl)); \
isc__rwlock_init(*rwl, rq, wq); \
}
#define isc_rwlock_lock(rwl, type) isc___rwlock_lock(*rwl, type)
#define isc_rwlock_trylock(rwl, type) isc___rwlock_trylock(*rwl, type)
#define isc_rwlock_unlock(rwl, type) isc___rwlock_unlock(*rwl, type)
#define isc_rwlock_tryupgrade(rwl) isc___rwlock_tryupgrade(*rwl)
#define isc_rwlock_downgrade(rwl) isc___rwlock_downgrade(*rwl)
#define isc_rwlock_destroy(rwl) \
{ \
isc___rwlock_destroy(*rwl); \
free(*rwl); \
}
#else /* ISC_TRACK_PTHREADS_OBJECTS */
typedef struct isc_rwlock isc_rwlock_t;
typedef struct isc_rwlock isc__rwlock_t;
#define isc_rwlock_init(rwl, rq, wq) isc__rwlock_init(rwl, rq, wq)
#define isc_rwlock_lock(rwl, type) isc___rwlock_lock(rwl, type)
#define isc_rwlock_trylock(rwl, type) isc___rwlock_trylock(rwl, type)
#define isc_rwlock_unlock(rwl, type) isc___rwlock_unlock(rwl, type)
#define isc_rwlock_tryupgrade(rwl) isc___rwlock_tryupgrade(rwl)
#define isc_rwlock_downgrade(rwl) isc___rwlock_downgrade(rwl)
#define isc_rwlock_destroy(rwl) isc___rwlock_destroy(rwl)
#endif /* ISC_TRACK_PTHREADS_OBJECTS */
#else /* USE_PTHREAD_RWLOCK */
struct isc_rwlock {
@@ -76,28 +114,45 @@ struct isc_rwlock {
unsigned int write_quota;
};
typedef struct isc_rwlock isc_rwlock_t;
typedef struct isc_rwlock isc__rwlock_t;
#define isc_rwlock_init(rwl, rq, wq) isc__rwlock_init(rwl, rq, wq)
#define isc_rwlock_lock(rwl, type) isc___rwlock_lock(rwl, type)
#define isc_rwlock_trylock(rwl, type) isc___rwlock_trylock(rwl, type)
#define isc_rwlock_unlock(rwl, type) isc___rwlock_unlock(rwl, type)
#define isc_rwlock_tryupgrade(rwl) isc___rwlock_tryupgrade(rwl)
#define isc_rwlock_downgrade(rwl) isc___rwlock_downgrade(rwl)
#define isc_rwlock_destroy(rwl) isc___rwlock_destroy(rwl)
#endif /* USE_PTHREAD_RWLOCK */
void
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota);
#define isc__rwlock_init(rwl, rq, wq) \
{ \
int _ret = isc___rwlock_init(rwl, rq, wq); \
ERRNO_CHECK(isc___rwlock_init, _ret); \
}
int
isc___rwlock_init(isc__rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota);
void
isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
isc___rwlock_lock(isc__rwlock_t *rwl, isc_rwlocktype_t type);
isc_result_t
isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
isc___rwlock_trylock(isc__rwlock_t *rwl, isc_rwlocktype_t type);
void
isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
isc___rwlock_unlock(isc__rwlock_t *rwl, isc_rwlocktype_t type);
isc_result_t
isc_rwlock_tryupgrade(isc_rwlock_t *rwl);
isc___rwlock_tryupgrade(isc__rwlock_t *rwl);
void
isc_rwlock_downgrade(isc_rwlock_t *rwl);
isc___rwlock_downgrade(isc__rwlock_t *rwl);
void
isc_rwlock_destroy(isc_rwlock_t *rwl);
isc___rwlock_destroy(isc__rwlock_t *rwl);
ISC_LANG_ENDDECLS

View File

@@ -72,7 +72,6 @@ typedef struct isc_quota isc_quota_t; /*%< Quota */
typedef struct isc_ratelimiter isc_ratelimiter_t; /*%< Rate Limiter */
typedef struct isc_region isc_region_t; /*%< Region */
typedef uint64_t isc_resourcevalue_t; /*%< Resource Value */
typedef struct isc_rwlock isc_rwlock_t; /*%< Read Write Lock */
typedef struct isc_sockaddr isc_sockaddr_t; /*%< Socket Address */
typedef ISC_LIST(isc_sockaddr_t) isc_sockaddrlist_t; /*%< Socket Address List
* */

View File

@@ -32,21 +32,22 @@
#include <errno.h>
#include <pthread.h>
void
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota) {
int
isc___rwlock_init(isc__rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota) {
int ret;
UNUSED(read_quota);
UNUSED(write_quota);
ret = pthread_rwlock_init(&rwl->rwlock, NULL);
ERRNO_CHECK(pthread_rwlock_init, ret);
atomic_init(&rwl->downgrade, false);
return (ret);
}
void
isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc___rwlock_lock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
switch (type) {
case isc_rwlocktype_read:
RUNTIME_CHECK(pthread_rwlock_rdlock(&rwl->rwlock) == 0);
@@ -71,7 +72,7 @@ isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
}
isc_result_t
isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc___rwlock_trylock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
int ret = 0;
switch (type) {
case isc_rwlocktype_read:
@@ -101,19 +102,19 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
}
void
isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc___rwlock_unlock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
UNUSED(type);
RUNTIME_CHECK(pthread_rwlock_unlock(&rwl->rwlock) == 0);
}
isc_result_t
isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
isc___rwlock_tryupgrade(isc__rwlock_t *rwl) {
UNUSED(rwl);
return (ISC_R_LOCKBUSY);
}
void
isc_rwlock_downgrade(isc_rwlock_t *rwl) {
isc___rwlock_downgrade(isc__rwlock_t *rwl) {
atomic_store_release(&rwl->downgrade, true);
RUNTIME_CHECK(pthread_rwlock_unlock(&rwl->rwlock) == 0);
RUNTIME_CHECK(pthread_rwlock_rdlock(&rwl->rwlock) == 0);
@@ -121,7 +122,7 @@ isc_rwlock_downgrade(isc_rwlock_t *rwl) {
}
void
isc_rwlock_destroy(isc_rwlock_t *rwl) {
isc___rwlock_destroy(isc__rwlock_t *rwl) {
pthread_rwlock_destroy(&rwl->rwlock);
}
@@ -165,16 +166,13 @@ isc_rwlock_destroy(isc_rwlock_t *rwl) {
#define isc_rwlock_pause()
#endif /* if defined(_MSC_VER) */
static void
isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
#ifdef ISC_RWLOCK_TRACE
#include <stdio.h> /* Required for fprintf/stderr. */
#include <isc/thread.h> /* Required for isc_thread_self(). */
static void
print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
print_lock(const char *operation, isc__rwlock_t *rwl, isc_rwlocktype_t type) {
fprintf(stderr,
"rwlock %p thread %" PRIuPTR " %s(%s): "
"write_requests=%u, write_completions=%u, "
@@ -189,9 +187,9 @@ print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
}
#endif /* ISC_RWLOCK_TRACE */
void
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota) {
int
isc___rwlock_init(isc__rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota) {
REQUIRE(rwl != NULL);
/*
@@ -221,10 +219,12 @@ isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
isc_condition_init(&rwl->writeable);
rwl->magic = RWLOCK_MAGIC;
return (0);
}
void
isc_rwlock_destroy(isc_rwlock_t *rwl) {
isc___rwlock_destroy(isc__rwlock_t *rwl) {
REQUIRE(VALID_RWLOCK(rwl));
REQUIRE(atomic_load_acquire(&rwl->write_requests) ==
@@ -304,7 +304,7 @@ isc_rwlock_destroy(isc_rwlock_t *rwl) {
#define READER_INCR 0x2
static void
isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
rwlock_lock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
int32_t cntflag;
REQUIRE(VALID_RWLOCK(rwl));
@@ -421,14 +421,14 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
}
void
isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc___rwlock_lock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
int32_t cnt = 0;
int32_t spins = atomic_load_acquire(&rwl->spins) * 2 + 10;
int32_t max_cnt = ISC_MAX(spins, RWLOCK_MAX_ADAPTIVE_COUNT);
do {
if (cnt++ >= max_cnt) {
isc__rwlock_lock(rwl, type);
rwlock_lock(rwl, type);
break;
}
isc_rwlock_pause();
@@ -438,7 +438,7 @@ isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
}
isc_result_t
isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc___rwlock_trylock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
int32_t cntflag;
REQUIRE(VALID_RWLOCK(rwl));
@@ -505,7 +505,7 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
}
isc_result_t
isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
isc___rwlock_tryupgrade(isc__rwlock_t *rwl) {
REQUIRE(VALID_RWLOCK(rwl));
int_fast32_t reader_incr = READER_INCR;
@@ -534,7 +534,7 @@ isc_rwlock_tryupgrade(isc_rwlock_t *rwl) {
}
void
isc_rwlock_downgrade(isc_rwlock_t *rwl) {
isc___rwlock_downgrade(isc__rwlock_t *rwl) {
int32_t prev_readers;
REQUIRE(VALID_RWLOCK(rwl));
@@ -558,7 +558,7 @@ isc_rwlock_downgrade(isc_rwlock_t *rwl) {
}
void
isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc___rwlock_unlock(isc__rwlock_t *rwl, isc_rwlocktype_t type) {
int32_t prev_cnt;
REQUIRE(VALID_RWLOCK(rwl));