Add basic reentrancy-checking support, and allow arena_new to reenter.

This checks whether or not we're reentrant using thread-local data, and, if we
are, moves certain internal allocations to use arena 0 (which should be properly
initialized after bootstrapping).

The immediate thing this allows is spinning up threads in arena_new, which will
enable spinning up background threads there.
This commit is contained in:
David Goldblatt
2017-03-31 19:59:45 -07:00
committed by David Goldblatt
parent 0a0fcd3e6a
commit b407a65401
10 changed files with 170 additions and 47 deletions

View File

@@ -10,31 +10,56 @@ static const char * test_name = "";
/* Reentrancy testing helpers. */
#define NUM_REENTRANT_ALLOCS 20
static bool reentrant = false;
static bool hook_ran = false;
static void *to_free[NUM_REENTRANT_ALLOCS];
typedef enum {
non_reentrant = 0,
libc_reentrant = 1,
arena_new_reentrant = 2
} reentrancy_t;
static reentrancy_t reentrancy;
static bool libc_hook_ran = false;
static bool arena_new_hook_ran = false;
static const char *
reentrancy_t_str(reentrancy_t r) {
switch (r) {
case non_reentrant:
return "non-reentrant";
case libc_reentrant:
return "libc-reentrant";
case arena_new_reentrant:
return "arena_new-reentrant";
default:
unreachable();
}
}
static void
reentrancy_hook() {
hook_ran = true;
hooks_libc_hook = NULL;
do_hook(bool *hook_ran, void (**hook)()) {
*hook_ran = true;
*hook = NULL;
void *to_free_local[NUM_REENTRANT_ALLOCS];
size_t alloc_size = 1;
for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) {
to_free[i] = malloc(alloc_size);
to_free_local[i] = malloc(alloc_size);
free(malloc(alloc_size));
alloc_size *= 2;
}
for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) {
free(to_free_local[i]);
}
}
static void
libc_reentrancy_hook() {
do_hook(&libc_hook_ran, &hooks_libc_hook);
}
static void
arena_new_reentrancy_hook() {
do_hook(&arena_new_hook_ran, &hooks_arena_new_hook);
}
/* Actual test infrastructure. */
bool
test_is_reentrant() {
return reentrant;
return reentrancy != non_reentrant;
}
JEMALLOC_FORMAT_PRINTF(1, 2)
@@ -81,9 +106,8 @@ p_test_init(const char *name) {
void
p_test_fini(void) {
test_counts[test_status]++;
malloc_printf("%s: %s (%s)\n", test_name,
test_status_string(test_status),
reentrant ? "reentrant" : "non-reentrant");
malloc_printf("%s (%s): %s\n", test_name, reentrancy_t_str(reentrancy),
test_status_string(test_status));
}
static test_status_t
@@ -106,24 +130,28 @@ p_test_impl(bool do_malloc_init, bool do_reentrant, test_t *t, va_list ap) {
ret = test_status_pass;
for (; t != NULL; t = va_arg(ap, test_t *)) {
/* Non-reentrant run. */
reentrant = false;
reentrancy = non_reentrant;
hooks_arena_new_hook = hooks_libc_hook = NULL;
t();
if (test_status > ret) {
ret = test_status;
}
/* Reentrant run. */
if (do_reentrant) {
reentrant = true;
hooks_libc_hook = &reentrancy_hook;
reentrancy = libc_reentrant;
hooks_arena_new_hook = NULL;
hooks_libc_hook = &libc_reentrancy_hook;
t();
if (test_status > ret) {
ret = test_status;
}
if (hook_ran) {
hook_ran = false;
for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) {
free(to_free[i]);
}
reentrancy = arena_new_reentrant;
hooks_libc_hook = NULL;
hooks_arena_new_hook = &arena_new_reentrancy_hook;
t();
if (test_status > ret) {
ret = test_status;
}
}
}

View File

@@ -156,7 +156,7 @@ TEST_END
int
main(void) {
return test(
return test_no_reentrancy(
test_malloc_vs_mallocx,
test_free_vs_dallocx,
test_dallocx_vs_sdallocx,

View File

@@ -351,7 +351,7 @@ TEST_END
int
main(void) {
return test(
return test_no_reentrancy(
test_stats_summary,
test_stats_large,
test_stats_arenas_summary,

View File

@@ -79,7 +79,6 @@ thd_start(void *arg) {
}
TEST_BEGIN(test_tsd_main_thread) {
test_skip_if(test_is_reentrant());
thd_start((void *)(uintptr_t)0xa5f3e329);
}
TEST_END
@@ -144,7 +143,7 @@ main(void) {
data_tsd_boot();
data_test_started = true;
return test(
return test_no_reentrancy(
test_tsd_main_thread,
test_tsd_sub_thread,
test_tsd_reincarnation);