Fix FreeBSD system jemalloc TSD cleanup

Before this commit, in case FreeBSD libc jemalloc was overridden by another
jemalloc, proper thread shutdown callback was involved only for the overriding
jemalloc. A call to _malloc_thread_cleanup from libthr would be redirected to
user jemalloc, leaving data about dead threads hanging in system jemalloc. This
change tackles the issue in two ways. First, for current and old system
jemallocs, which we can not modify, the overriding jemalloc would locate and
invoke system cleanup routine. For upcoming jemalloc integrations, the cleanup
registering function will also be redirected to user jemalloc, which means that
system jemalloc's cleanup routine will be registered in user's jemalloc and a
single call to _malloc_thread_cleanup will be sufficient to invoke both
callbacks.
This commit is contained in:
Alex Lapenkov 2022-01-22 10:14:16 -08:00 committed by Alexander Lapenkov
parent 78b58379c8
commit eb65d1b078
6 changed files with 19 additions and 10 deletions

View File

@ -1999,7 +1999,7 @@ AC_CHECK_FUNC([_malloc_thread_cleanup],
) )
if test "x$have__malloc_thread_cleanup" = "x1" ; then if test "x$have__malloc_thread_cleanup" = "x1" ; then
AC_DEFINE([JEMALLOC_MALLOC_THREAD_CLEANUP], [ ], [ ]) AC_DEFINE([JEMALLOC_MALLOC_THREAD_CLEANUP], [ ], [ ])
wrap_syms="${wrap_syms} _malloc_thread_cleanup" wrap_syms="${wrap_syms} _malloc_thread_cleanup _malloc_tsd_cleanup_register"
force_tls="1" force_tls="1"
fi fi

View File

@ -153,9 +153,12 @@ typedef ql_elm(tsd_t) tsd_link_t;
TSD_DATA_SLOWER_INITIALIZER \ TSD_DATA_SLOWER_INITIALIZER \
} }
#if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
void _malloc_tsd_cleanup_register(bool (*f)(void));
#endif
void *malloc_tsd_malloc(size_t size); void *malloc_tsd_malloc(size_t size);
void malloc_tsd_dalloc(void *wrapper); void malloc_tsd_dalloc(void *wrapper);
void malloc_tsd_cleanup_register(bool (*f)(void));
tsd_t *malloc_tsd_boot0(void); tsd_t *malloc_tsd_boot0(void);
void malloc_tsd_boot1(void); void malloc_tsd_boot1(void);
void tsd_cleanup(void *arg); void tsd_cleanup(void *arg);

View File

@ -21,7 +21,7 @@ tsd_cleanup_wrapper(void) {
JEMALLOC_ALWAYS_INLINE bool JEMALLOC_ALWAYS_INLINE bool
tsd_boot0(void) { tsd_boot0(void) {
malloc_tsd_cleanup_register(&tsd_cleanup_wrapper); _malloc_tsd_cleanup_register(&tsd_cleanup_wrapper);
tsd_booted = true; tsd_booted = true;
return false; return false;
} }

View File

@ -1,7 +1,7 @@
#ifndef JEMALLOC_INTERNAL_TSD_TYPES_H #ifndef JEMALLOC_INTERNAL_TSD_TYPES_H
#define JEMALLOC_INTERNAL_TSD_TYPES_H #define JEMALLOC_INTERNAL_TSD_TYPES_H
#define MALLOC_TSD_CLEANUPS_MAX 2 #define MALLOC_TSD_CLEANUPS_MAX 4
typedef struct tsd_s tsd_t; typedef struct tsd_s tsd_t;
typedef struct tsdn_s tsdn_t; typedef struct tsdn_s tsdn_t;

View File

@ -72,7 +72,7 @@ tsd_boot0(void) {
if (tsd_tsd == TLS_OUT_OF_INDEXES) { if (tsd_tsd == TLS_OUT_OF_INDEXES) {
return true; return true;
} }
malloc_tsd_cleanup_register(&tsd_cleanup_wrapper); _malloc_tsd_cleanup_register(&tsd_cleanup_wrapper);
tsd_wrapper_set(&tsd_boot_wrapper); tsd_wrapper_set(&tsd_boot_wrapper);
tsd_booted = true; tsd_booted = true;
return false; return false;

View File

@ -9,9 +9,6 @@
/******************************************************************************/ /******************************************************************************/
/* Data. */ /* Data. */
static unsigned ncleanups;
static malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX];
/* TSD_INITIALIZER triggers "-Wmissing-field-initializer" */ /* TSD_INITIALIZER triggers "-Wmissing-field-initializer" */
JEMALLOC_DIAGNOSTIC_PUSH JEMALLOC_DIAGNOSTIC_PUSH
JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
@ -337,6 +334,9 @@ malloc_tsd_dalloc(void *wrapper) {
} }
#if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32) #if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
static unsigned ncleanups;
static malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX];
#ifndef _WIN32 #ifndef _WIN32
JEMALLOC_EXPORT JEMALLOC_EXPORT
#endif #endif
@ -361,15 +361,19 @@ _malloc_thread_cleanup(void) {
} }
} while (again); } while (again);
} }
#endif
#ifndef _WIN32
JEMALLOC_EXPORT
#endif
void void
malloc_tsd_cleanup_register(bool (*f)(void)) { _malloc_tsd_cleanup_register(bool (*f)(void)) {
assert(ncleanups < MALLOC_TSD_CLEANUPS_MAX); assert(ncleanups < MALLOC_TSD_CLEANUPS_MAX);
cleanups[ncleanups] = f; cleanups[ncleanups] = f;
ncleanups++; ncleanups++;
} }
#endif
static void static void
tsd_do_data_cleanup(tsd_t *tsd) { tsd_do_data_cleanup(tsd_t *tsd) {
prof_tdata_cleanup(tsd); prof_tdata_cleanup(tsd);
@ -429,7 +433,9 @@ tsd_t *
malloc_tsd_boot0(void) { malloc_tsd_boot0(void) {
tsd_t *tsd; tsd_t *tsd;
#if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
ncleanups = 0; ncleanups = 0;
#endif
if (malloc_mutex_init(&tsd_nominal_tsds_lock, "tsd_nominal_tsds_lock", if (malloc_mutex_init(&tsd_nominal_tsds_lock, "tsd_nominal_tsds_lock",
WITNESS_RANK_OMIT, malloc_mutex_rank_exclusive)) { WITNESS_RANK_OMIT, malloc_mutex_rank_exclusive)) {
return NULL; return NULL;