Do proper cleanup for tsd_state_reincarnated.

Also enable arena_bind under non-nominal state, as the cleanup will be handled
correctly now.
This commit is contained in:
Qi Wang 2017-03-29 17:00:52 -07:00 committed by Qi Wang
parent 51d3682950
commit d3cda3423c
4 changed files with 50 additions and 18 deletions

View File

@ -74,7 +74,8 @@ tsd_##n##_get(tsd_t *tsd) { \
} \ } \
JEMALLOC_ALWAYS_INLINE void \ JEMALLOC_ALWAYS_INLINE void \
tsd_##n##_set(tsd_t *tsd, t n) { \ tsd_##n##_set(tsd_t *tsd, t n) { \
assert(tsd->state == tsd_state_nominal); \ assert(tsd->state == tsd_state_nominal || \
tsd->state == tsd_state_reincarnated); \
tsd->n = n; \ tsd->n = n; \
} }
#define MALLOC_TSD_getset_no(n, t) #define MALLOC_TSD_getset_no(n, t)

View File

@ -422,13 +422,7 @@ arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
static void static void
arena_bind(tsd_t *tsd, unsigned ind, bool internal) { arena_bind(tsd_t *tsd, unsigned ind, bool internal) {
arena_t *arena; arena_t *arena = arena_get(tsd_tsdn(tsd), ind, false);
if (!tsd_nominal(tsd)) {
return;
}
arena = arena_get(tsd_tsdn(tsd), ind, false);
arena_nthreads_inc(arena, internal); arena_nthreads_inc(arena, internal);
if (internal) { if (internal) {
@ -455,6 +449,7 @@ arena_unbind(tsd_t *tsd, unsigned ind, bool internal) {
arena = arena_get(tsd_tsdn(tsd), ind, false); arena = arena_get(tsd_tsdn(tsd), ind, false);
arena_nthreads_dec(arena, internal); arena_nthreads_dec(arena, internal);
if (internal) { if (internal) {
tsd_iarena_set(tsd, NULL); tsd_iarena_set(tsd, NULL);
} else { } else {

View File

@ -86,6 +86,12 @@ tsd_cleanup(void *arg) {
/* Do nothing. */ /* Do nothing. */
break; break;
case tsd_state_nominal: case tsd_state_nominal:
case tsd_state_reincarnated:
/*
* Reincarnated means another destructor deallocated memory
* after this destructor was called. Reset state to
* tsd_state_purgatory and request another callback.
*/
#define MALLOC_TSD_cleanup_yes(n, t) \ #define MALLOC_TSD_cleanup_yes(n, t) \
n##_cleanup(tsd); n##_cleanup(tsd);
#define MALLOC_TSD_cleanup_no(n, t) #define MALLOC_TSD_cleanup_no(n, t)
@ -106,15 +112,6 @@ MALLOC_TSD
* nothing, and do not request another callback. * nothing, and do not request another callback.
*/ */
break; break;
case tsd_state_reincarnated:
/*
* Another destructor deallocated memory after this destructor
* was called. Reset state to tsd_state_purgatory and request
* another callback.
*/
tsd->state = tsd_state_purgatory;
tsd_set(tsd);
break;
default: default:
not_reached(); not_reached();
} }

View File

@ -90,6 +90,44 @@ TEST_BEGIN(test_tsd_sub_thread) {
} }
TEST_END TEST_END
static void *
thd_start_reincarnated(void *arg) {
tsd_t *tsd = tsd_fetch();
assert(tsd);
void *p = malloc(1);
assert_ptr_not_null(p, "Unexpected malloc() failure");
/* Manually trigger reincarnation. */
assert_ptr_not_null(tsd->arena, "Should have tsd arena set.");
tsd_cleanup((void *)tsd);
assert_ptr_null(tsd->arena, "TSD arena should have been cleared.");
assert_u_eq(tsd->state, tsd_state_purgatory,
"TSD state should be purgatory\n");
free(p);
assert_u_eq(tsd->state, tsd_state_reincarnated,
"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,
"Should have tsd arena set after reincarnation.");
free(p);
tsd_cleanup((void *)tsd);
assert_ptr_null(tsd->arena,
"TSD arena should have been cleared after 2nd cleanup.");
return NULL;
}
TEST_BEGIN(test_tsd_reincarnation) {
thd_t thd;
thd_create(&thd, thd_start_reincarnated, NULL);
thd_join(thd, NULL);
}
TEST_END
int int
main(void) { main(void) {
/* Core tsd bootstrapping must happen prior to data_tsd_boot(). */ /* Core tsd bootstrapping must happen prior to data_tsd_boot(). */
@ -101,5 +139,6 @@ main(void) {
return test( return test(
test_tsd_main_thread, test_tsd_main_thread,
test_tsd_sub_thread); test_tsd_sub_thread,
test_tsd_reincarnation);
} }