Header refactoring: tsd - cleanup and dependency breaking.

This removes the tsd macros (which are used only for tsd_t in real builds).  We
break up the circular dependencies involving tsd.

We also move all tsd access through getters and setters.  This allows us to
assert that we only touch data when tsd is in a valid state.

We simplify the usages of the x macro trick, removing all the customizability
(get/set, init, cleanup), moving the lifetime logic to tsd_init and tsd_cleanup.
This lets us make initialization order independent of order within tsd_t.
This commit is contained in:
David Goldblatt
2017-04-26 18:37:44 -07:00
committed by David Goldblatt
parent c86c8f4ffb
commit 209f2926b8
29 changed files with 870 additions and 913 deletions

View File

@@ -1,41 +1,29 @@
#include "test/jemalloc_test.h"
#define THREAD_DATA 0x72b65c10
typedef unsigned int data_t;
static bool data_cleanup_executed;
static bool data_test_started;
malloc_tsd_types(data_, data_t)
malloc_tsd_protos(, data_, data_t)
static int data_cleanup_count;
void
data_cleanup(void *arg) {
data_t *data = (data_t *)arg;
if (!data_test_started) {
return;
}
if (!data_cleanup_executed) {
assert_x_eq(*data, THREAD_DATA,
data_cleanup(int *data) {
if (data_cleanup_count == 0) {
assert_x_eq(*data, MALLOC_TSD_TEST_DATA_INIT,
"Argument passed into cleanup function should match tsd "
"value");
}
data_cleanup_executed = true;
++data_cleanup_count;
/*
* Allocate during cleanup for two rounds, in order to assure that
* jemalloc's internal tsd reinitialization happens.
*/
bool reincarnate = false;
switch (*data) {
case THREAD_DATA:
case MALLOC_TSD_TEST_DATA_INIT:
*data = 1;
data_tsd_set(data);
reincarnate = true;
break;
case 1:
*data = 2;
data_tsd_set(data);
reincarnate = true;
break;
case 2:
return;
@@ -43,37 +31,35 @@ data_cleanup(void *arg) {
not_reached();
}
{
if (reincarnate) {
void *p = mallocx(1, 0);
assert_ptr_not_null(p, "Unexpeced mallocx() failure");
dallocx(p, 0);
}
}
malloc_tsd_externs(data_, data_t)
#define DATA_INIT 0x12345678
malloc_tsd_data(, data_, data_t, DATA_INIT)
malloc_tsd_funcs(, data_, data_t, DATA_INIT, data_cleanup)
static void *
thd_start(void *arg) {
data_t d = (data_t)(uintptr_t)arg;
int d = (int)(uintptr_t)arg;
void *p;
assert_x_eq(*data_tsd_get(true), DATA_INIT,
tsd_t *tsd = tsd_fetch();
assert_x_eq(tsd_test_data_get(tsd), MALLOC_TSD_TEST_DATA_INIT,
"Initial tsd get should return initialization value");
p = malloc(1);
assert_ptr_not_null(p, "Unexpected malloc() failure");
data_tsd_set(&d);
assert_x_eq(*data_tsd_get(true), d,
tsd_test_data_set(tsd, d);
assert_x_eq(tsd_test_data_get(tsd), d,
"After tsd set, tsd get should return value that was set");
d = 0;
assert_x_eq(*data_tsd_get(true), (data_t)(uintptr_t)arg,
assert_x_eq(tsd_test_data_get(tsd), (int)(uintptr_t)arg,
"Resetting local data should have no effect on tsd");
tsd_test_callback_set(tsd, &data_cleanup);
free(p);
return NULL;
}
@@ -86,11 +72,15 @@ TEST_END
TEST_BEGIN(test_tsd_sub_thread) {
thd_t thd;
data_cleanup_executed = false;
thd_create(&thd, thd_start, (void *)THREAD_DATA);
data_cleanup_count = 0;
thd_create(&thd, thd_start, (void *)MALLOC_TSD_TEST_DATA_INIT);
thd_join(thd, NULL);
assert_true(data_cleanup_executed,
"Cleanup function should have executed");
/*
* We reincarnate twice in the data cleanup, so it should execute at
* least 3 times.
*/
assert_x_ge(data_cleanup_count, 3,
"Cleanup function should have executed multiple times.");
}
TEST_END
@@ -103,9 +93,11 @@ thd_start_reincarnated(void *arg) {
assert_ptr_not_null(p, "Unexpected malloc() failure");
/* Manually trigger reincarnation. */
assert_ptr_not_null(tsd->arena, "Should have tsd arena set.");
assert_ptr_not_null(tsd_arena_get(tsd),
"Should have tsd arena set.");
tsd_cleanup((void *)tsd);
assert_ptr_null(tsd->arena, "TSD arena should have been cleared.");
assert_ptr_null(*tsd_arenap_get_unsafe(tsd),
"TSD arena should have been cleared.");
assert_u_eq(tsd->state, tsd_state_purgatory,
"TSD state should be purgatory\n");
@@ -114,12 +106,12 @@ thd_start_reincarnated(void *arg) {
"TSD state should be reincarnated\n");
p = mallocx(1, MALLOCX_TCACHE_NONE);
assert_ptr_not_null(p, "Unexpected malloc() failure");
assert_ptr_not_null(tsd->arena,
assert_ptr_not_null(*tsd_arenap_get_unsafe(tsd),
"Should have tsd arena set after reincarnation.");
free(p);
tsd_cleanup((void *)tsd);
assert_ptr_null(tsd->arena,
assert_ptr_null(*tsd_arenap_get_unsafe(tsd),
"TSD arena should have been cleared after 2nd cleanup.");
return NULL;
@@ -134,14 +126,11 @@ TEST_END
int
main(void) {
/* Core tsd bootstrapping must happen prior to data_tsd_boot(). */
/* Ensure tsd bootstrapped. */
if (nallocx(1, 0) == 0) {
malloc_printf("Initialization error");
return test_status_fail;
}
data_test_started = false;
data_tsd_boot();
data_test_started = true;
return test_no_reentrancy(
test_tsd_main_thread,