Skip to content

Commit 00869e3

Browse files
committed
Make tsd no-cleanup during tsd reincarnation.
Since tsd cleanup isn't guaranteed when reincarnated, we set up tsd in a way that needs no cleanup, by making it going through slow path instead.
1 parent 29c2577 commit 00869e3

File tree

4 files changed

+51
-24
lines changed

4 files changed

+51
-24
lines changed

include/jemalloc/internal/tsd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ void malloc_tsd_dalloc(void *wrapper);
154154
void malloc_tsd_cleanup_register(bool (*f)(void));
155155
tsd_t *malloc_tsd_boot0(void);
156156
void malloc_tsd_boot1(void);
157-
bool tsd_data_init(void *arg);
158157
void tsd_cleanup(void *arg);
159158
tsd_t *tsd_fetch_slow(tsd_t *tsd);
160159
void tsd_slow_update(tsd_t *tsd);
@@ -228,6 +227,7 @@ MALLOC_TSD
228227
#define O(n, t, nt) \
229228
JEMALLOC_ALWAYS_INLINE void \
230229
tsd_##n##_set(tsd_t *tsd, t val) { \
230+
assert(tsd->state != tsd_state_reincarnated); \
231231
*tsd_##n##p_get(tsd) = val; \
232232
}
233233
MALLOC_TSD

src/jemalloc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1764,7 +1764,8 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) {
17641764
* We should never specify particular arenas or tcaches from
17651765
* within our internal allocations.
17661766
*/
1767-
assert(dopts->tcache_ind == TCACHE_IND_AUTOMATIC);
1767+
assert(dopts->tcache_ind == TCACHE_IND_AUTOMATIC ||
1768+
dopts->tcache_ind == TCACHE_IND_NONE);
17681769
assert(dopts->arena_ind = ARENA_IND_AUTOMATIC);
17691770
dopts->tcache_ind = TCACHE_IND_NONE;
17701771
/* We know that arena 0 has already been initialized. */

src/tsd.c

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,45 @@ tsd_slow_update(tsd_t *tsd) {
6363
}
6464
}
6565

66+
static bool
67+
tsd_data_init(tsd_t *tsd) {
68+
/*
69+
* We initialize the rtree context first (before the tcache), since the
70+
* tcache initialization depends on it.
71+
*/
72+
rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd));
73+
74+
return tsd_tcache_enabled_data_init(tsd);
75+
}
76+
77+
static void
78+
assert_tsd_data_cleanup_done(tsd_t *tsd) {
79+
assert(!tsd_nominal(tsd));
80+
assert(*tsd_arenap_get_unsafe(tsd) == NULL);
81+
assert(*tsd_iarenap_get_unsafe(tsd) == NULL);
82+
assert(*tsd_arenas_tdata_bypassp_get_unsafe(tsd) == true);
83+
assert(*tsd_arenas_tdatap_get_unsafe(tsd) == NULL);
84+
assert(*tsd_tcache_enabledp_get_unsafe(tsd) == false);
85+
assert(*tsd_prof_tdatap_get_unsafe(tsd) == NULL);
86+
}
87+
88+
static bool
89+
tsd_data_init_nocleanup(tsd_t *tsd) {
90+
assert(tsd->state == tsd_state_reincarnated);
91+
/*
92+
* During reincarnation, there is no guarantee that the cleanup function
93+
* will be called (deallocation may happen after all tsd destructors).
94+
* We set up tsd in a way that no cleanup is needed.
95+
*/
96+
rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd));
97+
*tsd_arenas_tdata_bypassp_get(tsd) = true;
98+
*tsd_tcache_enabledp_get_unsafe(tsd) = false;
99+
*tsd_reentrancy_levelp_get(tsd) = 1;
100+
assert_tsd_data_cleanup_done(tsd);
101+
102+
return false;
103+
}
104+
66105
tsd_t *
67106
tsd_fetch_slow(tsd_t *tsd) {
68107
if (tsd->state == tsd_state_nominal_slow) {
@@ -79,7 +118,7 @@ tsd_fetch_slow(tsd_t *tsd) {
79118
} else if (tsd->state == tsd_state_purgatory) {
80119
tsd->state = tsd_state_reincarnated;
81120
tsd_set(tsd);
82-
tsd_data_init(tsd);
121+
tsd_data_init_nocleanup(tsd);
83122
} else {
84123
assert(tsd->state == tsd_state_reincarnated);
85124
}
@@ -131,21 +170,6 @@ malloc_tsd_cleanup_register(bool (*f)(void)) {
131170
ncleanups++;
132171
}
133172

134-
bool
135-
tsd_data_init(void *arg) {
136-
tsd_t *tsd = (tsd_t *)arg;
137-
/*
138-
* We initialize the rtree context first (before the tcache), since the
139-
* tcache initialization depends on it.
140-
*/
141-
rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd));
142-
143-
if (tsd_tcache_enabled_data_init(tsd)) {
144-
return true;
145-
}
146-
return false;
147-
}
148-
149173
static void
150174
tsd_do_data_cleanup(tsd_t *tsd) {
151175
prof_tdata_cleanup(tsd);
@@ -164,14 +188,16 @@ tsd_cleanup(void *arg) {
164188
case tsd_state_uninitialized:
165189
/* Do nothing. */
166190
break;
167-
case tsd_state_nominal:
168-
case tsd_state_nominal_slow:
169191
case tsd_state_reincarnated:
170192
/*
171193
* Reincarnated means another destructor deallocated memory
172-
* after this destructor was called. Reset state to
173-
* tsd_state_purgatory and request another callback.
194+
* after the destructor was called. Cleanup isn't required but
195+
* is still called for testing and completeness.
174196
*/
197+
assert_tsd_data_cleanup_done(tsd);
198+
/* Fall through. */
199+
case tsd_state_nominal:
200+
case tsd_state_nominal_slow:
175201
tsd_do_data_cleanup(tsd);
176202
tsd->state = tsd_state_purgatory;
177203
tsd_set(tsd);

test/unit/tsd.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ thd_start_reincarnated(void *arg) {
106106
"TSD state should be reincarnated\n");
107107
p = mallocx(1, MALLOCX_TCACHE_NONE);
108108
assert_ptr_not_null(p, "Unexpected malloc() failure");
109-
assert_ptr_not_null(*tsd_arenap_get_unsafe(tsd),
110-
"Should have tsd arena set after reincarnation.");
109+
assert_ptr_null(*tsd_arenap_get_unsafe(tsd),
110+
"Should not have tsd arena set after reincarnation.");
111111

112112
free(p);
113113
tsd_cleanup((void *)tsd);

0 commit comments

Comments
 (0)