summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQi Wang <interwq@gwu.edu>2017-03-30 00:00:52 (GMT)
committerQi Wang <interwq@gmail.com>2017-04-04 07:34:49 (GMT)
commitd3cda3423cd7ae47630833e4a888bdaf6a7bf8d9 (patch)
tree2d2d1200ae1c7a84201fed491bb9477d5c46339a
parent51d368295032910577d4f34b9ff99b3ed41544b9 (diff)
downloadjemalloc-d3cda3423cd7ae47630833e4a888bdaf6a7bf8d9.zip
jemalloc-d3cda3423cd7ae47630833e4a888bdaf6a7bf8d9.tar.gz
jemalloc-d3cda3423cd7ae47630833e4a888bdaf6a7bf8d9.tar.bz2
Do proper cleanup for tsd_state_reincarnated.
Also enable arena_bind under non-nominal state, as the cleanup will be handled correctly now.
-rw-r--r--include/jemalloc/internal/tsd_inlines.h3
-rw-r--r--src/jemalloc.c9
-rw-r--r--src/tsd.c15
-rw-r--r--test/unit/tsd.c41
4 files changed, 50 insertions, 18 deletions
diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h
index 7d57b7d..7c3fba5 100644
--- a/include/jemalloc/internal/tsd_inlines.h
+++ b/include/jemalloc/internal/tsd_inlines.h
@@ -74,7 +74,8 @@ tsd_##n##_get(tsd_t *tsd) { \
} \
JEMALLOC_ALWAYS_INLINE void \
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; \
}
#define MALLOC_TSD_getset_no(n, t)
diff --git a/src/jemalloc.c b/src/jemalloc.c
index ab047c2..7c8fe9c 100644
--- a/src/jemalloc.c
+++ b/src/jemalloc.c
@@ -422,13 +422,7 @@ arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
static void
arena_bind(tsd_t *tsd, unsigned ind, bool internal) {
- arena_t *arena;
-
- if (!tsd_nominal(tsd)) {
- return;
- }
-
- arena = arena_get(tsd_tsdn(tsd), ind, false);
+ arena_t *arena = arena_get(tsd_tsdn(tsd), ind, false);
arena_nthreads_inc(arena, 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_nthreads_dec(arena, internal);
+
if (internal) {
tsd_iarena_set(tsd, NULL);
} else {
diff --git a/src/tsd.c b/src/tsd.c
index 970d5ba..6b68c00 100644
--- a/src/tsd.c
+++ b/src/tsd.c
@@ -86,6 +86,12 @@ tsd_cleanup(void *arg) {
/* Do nothing. */
break;
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) \
n##_cleanup(tsd);
#define MALLOC_TSD_cleanup_no(n, t)
@@ -106,15 +112,6 @@ MALLOC_TSD
* nothing, and do not request another callback.
*/
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:
not_reached();
}
diff --git a/test/unit/tsd.c b/test/unit/tsd.c
index ae47d23..e033bb7 100644
--- a/test/unit/tsd.c
+++ b/test/unit/tsd.c
@@ -90,6 +90,44 @@ TEST_BEGIN(test_tsd_sub_thread) {
}
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
main(void) {
/* Core tsd bootstrapping must happen prior to data_tsd_boot(). */
@@ -101,5 +139,6 @@ main(void) {
return test(
test_tsd_main_thread,
- test_tsd_sub_thread);
+ test_tsd_sub_thread,
+ test_tsd_reincarnation);
}