From ebcfb16576295e802f2e54eed35bef660fdcf67f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 13 Jul 2022 13:19:32 +0200 Subject: [PATCH] Enable tracking of pthreads mutexes Some POSIX threads implementations (e.g. FreeBSD's libthr) allocate memory on the heap when pthread_mutex_init() is called. Every call to that function must be accompanied by a corresponding call to pthread_mutex_destroy() or else the memory allocated for the mutex 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 mutexes that allocate memory using malloc() and release it using free(). This enables using jemalloc for detecting missing pthread_mutex_destroy() calls on any platform on which it works reliably. Introduce a new ISC_TRACK_PTHREADS_OBJECTS preprocessor macro, which causes isc_mutex_t structures to be allocated on the heap by isc_mutex_init() and freed by isc_mutex_destroy(). Reuse existing mutex macros (after renaming them appropriately) for other operations. --- lib/isc/condition.c | 10 ++++++- lib/isc/include/isc/condition.h | 8 +++++- lib/isc/include/isc/mutex.h | 47 ++++++++++++++++++++++++++++----- lib/isc/mutex.c | 8 ------ 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/lib/isc/condition.c b/lib/isc/condition.c index 19c16be6b1..de412ec5ab 100644 --- a/lib/isc/condition.c +++ b/lib/isc/condition.c @@ -52,7 +52,15 @@ isc_condition_waituntil(isc_condition_t *c, isc_mutex_t *m, isc_time_t *t) { ts.tv_nsec = (long)isc_time_nanoseconds(t); do { - presult = pthread_cond_timedwait(c, m, &ts); + pthread_mutex_t *mutex; + +#ifdef ISC_TRACK_PTHREADS_OBJECTS + mutex = *m; +#else /* ISC_TRACK_PTHREADS_OBJECTS */ + mutex = m; +#endif /* ISC_TRACK_PTHREADS_OBJECTS */ + + presult = pthread_cond_timedwait(c, mutex, &ts); if (presult == 0) { return (ISC_R_SUCCESS); } diff --git a/lib/isc/include/isc/condition.h b/lib/isc/include/isc/condition.h index 69622d32ce..36fc128735 100644 --- a/lib/isc/include/isc/condition.h +++ b/lib/isc/include/isc/condition.h @@ -33,7 +33,13 @@ typedef pthread_cond_t isc_condition_t; ERRNO_CHECK(pthread_cond_init, _ret); \ } -#define isc_condition_wait(cp, mp) \ +#ifdef ISC_TRACK_PTHREADS_OBJECTS +#define isc_condition_wait(cp, mp) isc__condition_wait(cp, *mp) +#else /* ISC_TRACK_PTHREADS_OBJECTS */ +#define isc_condition_wait(cp, mp) isc__condition_wait(cp, mp) +#endif /* ISC_TRACK_PTHREADS_OBJECTS */ + +#define isc__condition_wait(cp, mp) \ RUNTIME_CHECK(pthread_cond_wait((cp), (mp)) == 0) #define isc_condition_signal(cp) RUNTIME_CHECK(pthread_cond_signal((cp)) == 0) diff --git a/lib/isc/include/isc/mutex.h b/lib/isc/include/isc/mutex.h index 09d192f610..028db239db 100644 --- a/lib/isc/include/isc/mutex.h +++ b/lib/isc/include/isc/mutex.h @@ -17,26 +17,59 @@ #include #include +#include #include #include /* for ISC_R_ codes */ +#include ISC_LANG_BEGINDECLS +#ifdef ISC_TRACK_PTHREADS_OBJECTS + +typedef pthread_mutex_t *isc_mutex_t; + +#define isc_mutex_init(mp) \ + { \ + *mp = malloc(sizeof(**mp)); \ + isc__mutex_init((*mp)); \ + } +#define isc_mutex_lock(mp) isc__mutex_lock(*mp) +#define isc_mutex_unlock(mp) isc__mutex_unlock(*mp) +#define isc_mutex_trylock(mp) isc__mutex_trylock(*mp) +#define isc_mutex_destroy(mp) \ + { \ + isc__mutex_destroy(*mp); \ + free(*mp); \ + } + +#else /* ISC_TRACK_PTHREADS_OBJECTS */ + typedef pthread_mutex_t isc_mutex_t; -void -isc__mutex_init(isc_mutex_t *mp); +#define isc_mutex_init(mp) isc__mutex_init((mp)) +#define isc_mutex_lock(mp) isc__mutex_lock(mp) +#define isc_mutex_unlock(mp) isc__mutex_unlock(mp) +#define isc_mutex_trylock(mp) isc__mutex_trylock(mp) +#define isc_mutex_destroy(mp) isc__mutex_destroy(mp) -#define isc_mutex_init(mp) isc__mutex_init((mp)) +#endif /* ISC_TRACK_PTHREADS_OBJECTS */ -#define isc_mutex_lock(mp) RUNTIME_CHECK(pthread_mutex_lock((mp)) == 0) +extern pthread_mutexattr_t isc__mutex_init_attr; -#define isc_mutex_unlock(mp) RUNTIME_CHECK(pthread_mutex_unlock((mp)) == 0) +#define isc__mutex_init(mp) \ + { \ + int _ret = pthread_mutex_init(mp, &isc__mutex_init_attr); \ + ERRNO_CHECK(pthread_mutex_init, _ret); \ + } -#define isc_mutex_trylock(mp) \ +#define isc__mutex_lock(mp) RUNTIME_CHECK(pthread_mutex_lock((mp)) == 0) + +#define isc__mutex_unlock(mp) RUNTIME_CHECK(pthread_mutex_unlock((mp)) == 0) + +#define isc__mutex_trylock(mp) \ ((pthread_mutex_trylock((mp)) == 0) ? ISC_R_SUCCESS : ISC_R_LOCKBUSY) -#define isc_mutex_destroy(mp) RUNTIME_CHECK(pthread_mutex_destroy((mp)) == 0) +#define isc__mutex_destroy(mp) RUNTIME_CHECK(pthread_mutex_destroy((mp)) == 0) ISC_LANG_ENDDECLS diff --git a/lib/isc/mutex.c b/lib/isc/mutex.c index 075fc37b32..9c067cbd9e 100644 --- a/lib/isc/mutex.c +++ b/lib/isc/mutex.c @@ -47,14 +47,6 @@ isc__mutex_initialize(void) { ISC_R_SUCCESS); } -void -isc__mutex_init(isc_mutex_t *mp) { - int err; - - err = pthread_mutex_init(mp, &isc__mutex_init_attr); - ERRNO_CHECK(pthread_mutex_init, err); -} - void isc__mutex_shutdown(void) { /* noop */;