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:
committed by
Michał Kępień
parent
8dfdb95a20
commit
e4606da2c6
@@ -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
|
||||
|
@@ -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
|
||||
* */
|
||||
|
@@ -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));
|
||||
|
Reference in New Issue
Block a user