]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Enable tracking of pthreads condition variables
authorOndřej Surý <ondrej@isc.org>
Wed, 13 Jul 2022 11:19:32 +0000 (13:19 +0200)
committerMichał Kępień <michal@isc.org>
Wed, 13 Jul 2022 11:19:32 +0000 (13:19 +0200)
Some POSIX threads implementations (e.g. FreeBSD's libthr) allocate
memory on the heap when pthread_cond_init() is called.  Every call to
that function must be accompanied by a corresponding call to
pthread_cond_destroy() or else the memory allocated for the condition
variable 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 condition variables that allocate memory using malloc() and
release it using free().  This enables using jemalloc for detecting
missing pthread_cond_destroy() calls on any platform on which it works
reliably.

When the newly introduced ISC_TRACK_PTHREADS_OBJECTS preprocessor macro
is set, allocate isc_condition_t structures on the heap in
isc_condition_init() and free them in isc_condition_destroy().  Reuse
existing condition variable macros (after renaming them appropriately)
for other operations.

lib/isc/condition.c
lib/isc/include/isc/condition.h

index de412ec5ab4c67f1e40bdb1a7145b437f60ad41b..0573c37e2f4cd8b3ba6eac15dbb4269fe580fc9c 100644 (file)
@@ -22,7 +22,7 @@
 #include <isc/util.h>
 
 isc_result_t
-isc_condition_waituntil(isc_condition_t *c, isc_mutex_t *m, isc_time_t *t) {
+isc__condition_waituntil(pthread_cond_t *c, pthread_mutex_t *m, isc_time_t *t) {
        int presult;
        isc_result_t result;
        struct timespec ts;
@@ -52,15 +52,7 @@ isc_condition_waituntil(isc_condition_t *c, isc_mutex_t *m, isc_time_t *t) {
        ts.tv_nsec = (long)isc_time_nanoseconds(t);
 
        do {
-               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);
+               presult = pthread_cond_timedwait(c, m, &ts);
                if (presult == 0) {
                        return (ISC_R_SUCCESS);
                }
index 36fc12873567480959df04061d4853d33f8cb0a9..63d0f9834306c7319d0154fa4b7ff0bf3d1ea142 100644 (file)
@@ -16,6 +16,7 @@
 /*! \file */
 
 #include <errno.h>
+#include <stdlib.h>
 
 #include <isc/error.h>
 #include <isc/lang.h>
 #include <isc/types.h>
 #include <isc/util.h>
 
+ISC_LANG_BEGINDECLS
+
+#ifdef ISC_TRACK_PTHREADS_OBJECTS
+
+typedef pthread_cond_t *isc_condition_t;
+
+#define isc_condition_init(cp)              \
+       {                                   \
+               *cp = malloc(sizeof(**cp)); \
+               isc__condition_init(*cp);   \
+       }
+#define isc_condition_wait(cp, mp)        isc__condition_wait(*cp, *mp)
+#define isc_condition_waituntil(cp, mp, t) isc__condition_waituntil(*cp, *mp, t)
+#define isc_condition_signal(cp)          isc__condition_signal(*cp)
+#define isc_condition_broadcast(cp)       isc__condition_broadcast(*cp)
+#define isc_condition_destroy(cp)            \
+       {                                    \
+               isc__condition_destroy(*cp); \
+               free(*cp);                   \
+       }
+
+#else /* ISC_TRACK_PTHREADS_OBJECTS */
+
 typedef pthread_cond_t isc_condition_t;
 
-#define isc_condition_init(cond)                          \
+#define isc_condition_init(cond)          isc__condition_init(cond)
+#define isc_condition_wait(cp, mp)        isc__condition_wait(cp, mp)
+#define isc_condition_waituntil(cp, mp, t) isc__condition_waituntil(cp, mp, t)
+#define isc_condition_signal(cp)          isc__condition_signal(cp)
+#define isc_condition_broadcast(cp)       isc__condition_broadcast(cp)
+#define isc_condition_destroy(cp)         isc__condition_destroy(cp)
+
+#endif /* ISC_TRACK_PTHREADS_OBJECTS */
+
+#define isc__condition_init(cond)                         \
        {                                                 \
                int _ret = pthread_cond_init(cond, NULL); \
                ERRNO_CHECK(pthread_cond_init, _ret);     \
        }
 
-#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)
+#define isc__condition_signal(cp) RUNTIME_CHECK(pthread_cond_signal((cp)) == 0)
 
-#define isc_condition_broadcast(cp) \
+#define isc__condition_broadcast(cp) \
        RUNTIME_CHECK(pthread_cond_broadcast((cp)) == 0)
 
-#define isc_condition_destroy(cp) RUNTIME_CHECK(pthread_cond_destroy((cp)) == 0)
-
-ISC_LANG_BEGINDECLS
+#define isc__condition_destroy(cp) \
+       RUNTIME_CHECK(pthread_cond_destroy((cp)) == 0)
 
 isc_result_t
-isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *);
+isc__condition_waituntil(pthread_cond_t *, pthread_mutex_t *, isc_time_t *);
 
 ISC_LANG_ENDDECLS