Fix tsd bootstrapping for a0malloc().

This commit is contained in:
Jason Evans 2016-05-07 12:42:31 -07:00
parent 919e4a0ea9
commit 0c12dcabc5
7 changed files with 101 additions and 43 deletions

View File

@ -135,6 +135,7 @@ C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \
$(srcroot)test/src/thd.c $(srcroot)test/src/timer.c $(srcroot)test/src/thd.c $(srcroot)test/src/timer.c
C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c
TESTS_UNIT := \ TESTS_UNIT := \
$(srcroot)test/unit/a0.c \
$(srcroot)test/unit/arena_reset.c \ $(srcroot)test/unit/arena_reset.c \
$(srcroot)test/unit/atomic.c \ $(srcroot)test/unit/atomic.c \
$(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/bitmap.c \

View File

@ -254,7 +254,7 @@ typedef struct {
* definition. * definition.
*/ */
static bool malloc_init_hard_a0(tsd_t *tsd); static bool malloc_init_hard_a0(void);
static bool malloc_init_hard(void); static bool malloc_init_hard(void);
/******************************************************************************/ /******************************************************************************/
@ -291,7 +291,7 @@ malloc_init_a0(void)
{ {
if (unlikely(malloc_init_state == malloc_init_uninitialized)) if (unlikely(malloc_init_state == malloc_init_uninitialized))
return (malloc_init_hard_a0(NULL)); return (malloc_init_hard_a0());
return (false); return (false);
} }
@ -307,7 +307,7 @@ malloc_init(void)
} }
/* /*
* The a0*() functions are used instead of i[mcd]alloc() in situations that * The a0*() functions are used instead of i{d,}alloc() in situations that
* cannot tolerate TLS variable access. * cannot tolerate TLS variable access.
*/ */
@ -318,8 +318,8 @@ a0ialloc(size_t size, bool zero, bool is_metadata)
if (unlikely(malloc_init_a0())) if (unlikely(malloc_init_a0()))
return (NULL); return (NULL);
return (iallocztm(NULL, size, size2index(size), zero, NULL, return (iallocztm(NULL, size, size2index(size), zero, NULL, is_metadata,
is_metadata, arena_get(NULL, 0, true), true)); arena_get(NULL, 0, true), true));
} }
static void static void
@ -1256,7 +1256,7 @@ malloc_init_hard_needed(void)
} }
static bool static bool
malloc_init_hard_a0_locked(tsd_t *tsd) malloc_init_hard_a0_locked(tsd_t **tsd)
{ {
malloc_initializer = INITIALIZER; malloc_initializer = INITIALIZER;
@ -1283,7 +1283,7 @@ malloc_init_hard_a0_locked(tsd_t *tsd)
prof_boot1(); prof_boot1();
if (arena_boot()) if (arena_boot())
return (true); return (true);
if (config_tcache && tcache_boot(tsd)) if (config_tcache && tcache_boot(*tsd))
return (true); return (true);
if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS)) if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS))
return (true); return (true);
@ -1299,38 +1299,41 @@ malloc_init_hard_a0_locked(tsd_t *tsd)
* Initialize one arena here. The rest are lazily created in * Initialize one arena here. The rest are lazily created in
* arena_choose_hard(). * arena_choose_hard().
*/ */
if (arena_init(tsd, 0) == NULL) if (arena_init(*tsd, 0) == NULL)
return (true); return (true);
/*
* Initialize tsd, since some code paths cause chunk allocation, which
* in turn depends on tsd.
*/
*tsd = malloc_tsd_boot0();
if (*tsd == NULL)
return (true);
malloc_init_state = malloc_init_a0_initialized; malloc_init_state = malloc_init_a0_initialized;
return (false); return (false);
} }
static bool static bool
malloc_init_hard_a0(tsd_t *tsd) malloc_init_hard_a0(void)
{ {
bool ret; bool ret;
tsd_t *tsd = NULL;
malloc_mutex_lock(tsd, &init_lock); malloc_mutex_lock(tsd, &init_lock);
ret = malloc_init_hard_a0_locked(tsd); ret = malloc_init_hard_a0_locked(&tsd);
malloc_mutex_unlock(tsd, &init_lock); malloc_mutex_unlock(tsd, &init_lock);
return (ret); return (ret);
} }
/* Initialize data structures which may trigger recursive allocation. */ /* Initialize data structures which may trigger recursive allocation. */
static bool static bool
malloc_init_hard_recursible(tsd_t **tsd) malloc_init_hard_recursible(tsd_t *tsd)
{ {
bool ret;
malloc_init_state = malloc_init_recursible; malloc_init_state = malloc_init_recursible;
malloc_mutex_unlock(*tsd, &init_lock); malloc_mutex_unlock(tsd, &init_lock);
/* LinuxThreads' pthread_setspecific() allocates. */
*tsd = malloc_tsd_boot0();
if (*tsd == NULL) {
ret = true;
goto label_return;
}
ncpus = malloc_ncpus(); ncpus = malloc_ncpus();
@ -1339,17 +1342,16 @@ malloc_init_hard_recursible(tsd_t **tsd)
/* LinuxThreads' pthread_atfork() allocates. */ /* LinuxThreads' pthread_atfork() allocates. */
if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent, if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent,
jemalloc_postfork_child) != 0) { jemalloc_postfork_child) != 0) {
ret = true;
malloc_write("<jemalloc>: Error in pthread_atfork()\n"); malloc_write("<jemalloc>: Error in pthread_atfork()\n");
if (opt_abort) if (opt_abort)
abort(); abort();
malloc_mutex_lock(tsd, &init_lock);
return (true);
} }
#endif #endif
ret = false; malloc_mutex_lock(tsd, &init_lock);
label_return: return (false);
malloc_mutex_lock(*tsd, &init_lock);
return (ret);
} }
static bool static bool
@ -1409,12 +1411,12 @@ malloc_init_hard(void)
} }
if (malloc_init_state != malloc_init_a0_initialized && if (malloc_init_state != malloc_init_a0_initialized &&
malloc_init_hard_a0_locked(tsd)) { malloc_init_hard_a0_locked(&tsd)) {
malloc_mutex_unlock(tsd, &init_lock); malloc_mutex_unlock(tsd, &init_lock);
return (true); return (true);
} }
if (malloc_init_hard_recursible(&tsd)) { if (malloc_init_hard_recursible(tsd)) {
malloc_mutex_unlock(tsd, &init_lock); malloc_mutex_unlock(tsd, &init_lock);
return (true); return (true);
} }
@ -2669,6 +2671,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)
* to trigger the deadlock described above, but doing so would involve forking * to trigger the deadlock described above, but doing so would involve forking
* via a library constructor that runs before jemalloc's runs. * via a library constructor that runs before jemalloc's runs.
*/ */
#ifndef JEMALLOC_JET
JEMALLOC_ATTR(constructor) JEMALLOC_ATTR(constructor)
static void static void
jemalloc_constructor(void) jemalloc_constructor(void)
@ -2676,6 +2679,7 @@ jemalloc_constructor(void)
malloc_init(); malloc_init();
} }
#endif
#ifndef JEMALLOC_MUTEX_INIT_CB #ifndef JEMALLOC_MUTEX_INIT_CB
void void

View File

@ -311,6 +311,9 @@ label_test_end: \
#define test(...) \ #define test(...) \
p_test(__VA_ARGS__, NULL) p_test(__VA_ARGS__, NULL)
#define test_no_malloc_init(...) \
p_test_no_malloc_init(__VA_ARGS__, NULL)
#define test_skip_if(e) do { \ #define test_skip_if(e) do { \
if (e) { \ if (e) { \
test_skip("%s:%s:%d: Test skipped: (%s)", \ test_skip("%s:%s:%d: Test skipped: (%s)", \
@ -324,6 +327,7 @@ void test_fail(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2);
/* For private use by macros. */ /* For private use by macros. */
test_status_t p_test(test_t *t, ...); test_status_t p_test(test_t *t, ...);
test_status_t p_test_no_malloc_init(test_t *t, ...);
void p_test_init(const char *name); void p_test_init(const char *name);
void p_test_fini(void); void p_test_fini(void);
void p_test_fail(const char *prefix, const char *message); void p_test_fail(const char *prefix, const char *message);

View File

@ -60,32 +60,30 @@ p_test_fini(void)
malloc_printf("%s: %s\n", test_name, test_status_string(test_status)); malloc_printf("%s: %s\n", test_name, test_status_string(test_status));
} }
test_status_t static test_status_t
p_test(test_t *t, ...) p_test_impl(bool do_malloc_init, test_t *t, va_list ap)
{ {
test_status_t ret; test_status_t ret;
va_list ap;
if (do_malloc_init) {
/* /*
* Make sure initialization occurs prior to running tests. Tests are * Make sure initialization occurs prior to running tests.
* special because they may use internal facilities prior to triggering * Tests are special because they may use internal facilities
* initialization as a side effect of calling into the public API. This * prior to triggering initialization as a side effect of
* is a final safety that works even if jemalloc_constructor() doesn't * calling into the public API.
* run, as for MSVC builds.
*/ */
if (nallocx(1, 0) == 0) { if (nallocx(1, 0) == 0) {
malloc_printf("Initialization error"); malloc_printf("Initialization error");
return (test_status_fail); return (test_status_fail);
} }
}
ret = test_status_pass; ret = test_status_pass;
va_start(ap, t);
for (; t != NULL; t = va_arg(ap, test_t *)) { for (; t != NULL; t = va_arg(ap, test_t *)) {
t(); t();
if (test_status > ret) if (test_status > ret)
ret = test_status; ret = test_status;
} }
va_end(ap);
malloc_printf("--- %s: %u/%u, %s: %u/%u, %s: %u/%u ---\n", malloc_printf("--- %s: %u/%u, %s: %u/%u, %s: %u/%u ---\n",
test_status_string(test_status_pass), test_status_string(test_status_pass),
@ -98,6 +96,34 @@ p_test(test_t *t, ...)
return (ret); return (ret);
} }
test_status_t
p_test(test_t *t, ...)
{
test_status_t ret;
va_list ap;
ret = test_status_pass;
va_start(ap, t);
ret = p_test_impl(true, t, ap);
va_end(ap);
return (ret);
}
test_status_t
p_test_no_malloc_init(test_t *t, ...)
{
test_status_t ret;
va_list ap;
ret = test_status_pass;
va_start(ap, t);
ret = p_test_impl(false, t, ap);
va_end(ap);
return (ret);
}
void void
p_test_fail(const char *prefix, const char *message) p_test_fail(const char *prefix, const char *message)
{ {

19
test/unit/a0.c Normal file
View File

@ -0,0 +1,19 @@
#include "test/jemalloc_test.h"
TEST_BEGIN(test_a0)
{
void *p;
p = a0malloc(1);
assert_ptr_not_null(p, "Unexpected a0malloc() error");
a0dalloc(p);
}
TEST_END
int
main(void)
{
return (test_no_malloc_init(
test_a0));
}

View File

@ -244,7 +244,6 @@ int
main(void) main(void)
{ {
assert(!config_fill || opt_junk_alloc || opt_junk_free);
return (test( return (test(
test_junk_small, test_junk_small,
test_junk_large, test_junk_large,

View File

@ -99,6 +99,11 @@ int
main(void) main(void)
{ {
/* Core tsd bootstrapping must happen prior to data_tsd_boot(). */
if (nallocx(1, 0) == 0) {
malloc_printf("Initialization error");
return (test_status_fail);
}
data_tsd_boot(); data_tsd_boot();
return (test( return (test(