1*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_TSD_C_
2*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_preamble.h"
3*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_internal_includes.h"
4*1208bc7eSAndroid Build Coastguard Worker
5*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/assert.h"
6*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/mutex.h"
7*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/rtree.h"
8*1208bc7eSAndroid Build Coastguard Worker
9*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
10*1208bc7eSAndroid Build Coastguard Worker /* Data. */
11*1208bc7eSAndroid Build Coastguard Worker
12*1208bc7eSAndroid Build Coastguard Worker static unsigned ncleanups;
13*1208bc7eSAndroid Build Coastguard Worker static malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX];
14*1208bc7eSAndroid Build Coastguard Worker
15*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
16*1208bc7eSAndroid Build Coastguard Worker __thread tsd_t JEMALLOC_TLS_MODEL tsd_tls = TSD_INITIALIZER;
17*1208bc7eSAndroid Build Coastguard Worker __thread bool JEMALLOC_TLS_MODEL tsd_initialized = false;
18*1208bc7eSAndroid Build Coastguard Worker bool tsd_booted = false;
19*1208bc7eSAndroid Build Coastguard Worker #elif (defined(JEMALLOC_TLS))
20*1208bc7eSAndroid Build Coastguard Worker __thread tsd_t JEMALLOC_TLS_MODEL tsd_tls = TSD_INITIALIZER;
21*1208bc7eSAndroid Build Coastguard Worker pthread_key_t tsd_tsd;
22*1208bc7eSAndroid Build Coastguard Worker bool tsd_booted = false;
23*1208bc7eSAndroid Build Coastguard Worker #elif (defined(_WIN32))
24*1208bc7eSAndroid Build Coastguard Worker DWORD tsd_tsd;
25*1208bc7eSAndroid Build Coastguard Worker tsd_wrapper_t tsd_boot_wrapper = {false, TSD_INITIALIZER};
26*1208bc7eSAndroid Build Coastguard Worker bool tsd_booted = false;
27*1208bc7eSAndroid Build Coastguard Worker #else
28*1208bc7eSAndroid Build Coastguard Worker
29*1208bc7eSAndroid Build Coastguard Worker /*
30*1208bc7eSAndroid Build Coastguard Worker * This contains a mutex, but it's pretty convenient to allow the mutex code to
31*1208bc7eSAndroid Build Coastguard Worker * have a dependency on tsd. So we define the struct here, and only refer to it
32*1208bc7eSAndroid Build Coastguard Worker * by pointer in the header.
33*1208bc7eSAndroid Build Coastguard Worker */
34*1208bc7eSAndroid Build Coastguard Worker struct tsd_init_head_s {
35*1208bc7eSAndroid Build Coastguard Worker ql_head(tsd_init_block_t) blocks;
36*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_t lock;
37*1208bc7eSAndroid Build Coastguard Worker };
38*1208bc7eSAndroid Build Coastguard Worker
39*1208bc7eSAndroid Build Coastguard Worker pthread_key_t tsd_tsd;
40*1208bc7eSAndroid Build Coastguard Worker tsd_init_head_t tsd_init_head = {
41*1208bc7eSAndroid Build Coastguard Worker ql_head_initializer(blocks),
42*1208bc7eSAndroid Build Coastguard Worker MALLOC_MUTEX_INITIALIZER
43*1208bc7eSAndroid Build Coastguard Worker };
44*1208bc7eSAndroid Build Coastguard Worker tsd_wrapper_t tsd_boot_wrapper = {
45*1208bc7eSAndroid Build Coastguard Worker false,
46*1208bc7eSAndroid Build Coastguard Worker TSD_INITIALIZER
47*1208bc7eSAndroid Build Coastguard Worker };
48*1208bc7eSAndroid Build Coastguard Worker bool tsd_booted = false;
49*1208bc7eSAndroid Build Coastguard Worker #endif
50*1208bc7eSAndroid Build Coastguard Worker
51*1208bc7eSAndroid Build Coastguard Worker
52*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
53*1208bc7eSAndroid Build Coastguard Worker
54*1208bc7eSAndroid Build Coastguard Worker void
tsd_slow_update(tsd_t * tsd)55*1208bc7eSAndroid Build Coastguard Worker tsd_slow_update(tsd_t *tsd) {
56*1208bc7eSAndroid Build Coastguard Worker if (tsd_nominal(tsd)) {
57*1208bc7eSAndroid Build Coastguard Worker if (malloc_slow || !tsd_tcache_enabled_get(tsd) ||
58*1208bc7eSAndroid Build Coastguard Worker tsd_reentrancy_level_get(tsd) > 0) {
59*1208bc7eSAndroid Build Coastguard Worker tsd->state = tsd_state_nominal_slow;
60*1208bc7eSAndroid Build Coastguard Worker } else {
61*1208bc7eSAndroid Build Coastguard Worker tsd->state = tsd_state_nominal;
62*1208bc7eSAndroid Build Coastguard Worker }
63*1208bc7eSAndroid Build Coastguard Worker }
64*1208bc7eSAndroid Build Coastguard Worker }
65*1208bc7eSAndroid Build Coastguard Worker
66*1208bc7eSAndroid Build Coastguard Worker static bool
tsd_data_init(tsd_t * tsd)67*1208bc7eSAndroid Build Coastguard Worker tsd_data_init(tsd_t *tsd) {
68*1208bc7eSAndroid Build Coastguard Worker /*
69*1208bc7eSAndroid Build Coastguard Worker * We initialize the rtree context first (before the tcache), since the
70*1208bc7eSAndroid Build Coastguard Worker * tcache initialization depends on it.
71*1208bc7eSAndroid Build Coastguard Worker */
72*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd));
73*1208bc7eSAndroid Build Coastguard Worker
74*1208bc7eSAndroid Build Coastguard Worker /*
75*1208bc7eSAndroid Build Coastguard Worker * A nondeterministic seed based on the address of tsd reduces
76*1208bc7eSAndroid Build Coastguard Worker * the likelihood of lockstep non-uniform cache index
77*1208bc7eSAndroid Build Coastguard Worker * utilization among identical concurrent processes, but at the
78*1208bc7eSAndroid Build Coastguard Worker * cost of test repeatability. For debug builds, instead use a
79*1208bc7eSAndroid Build Coastguard Worker * deterministic seed.
80*1208bc7eSAndroid Build Coastguard Worker */
81*1208bc7eSAndroid Build Coastguard Worker *tsd_offset_statep_get(tsd) = config_debug ? 0 :
82*1208bc7eSAndroid Build Coastguard Worker (uint64_t)(uintptr_t)tsd;
83*1208bc7eSAndroid Build Coastguard Worker
84*1208bc7eSAndroid Build Coastguard Worker return tsd_tcache_enabled_data_init(tsd);
85*1208bc7eSAndroid Build Coastguard Worker }
86*1208bc7eSAndroid Build Coastguard Worker
87*1208bc7eSAndroid Build Coastguard Worker static void
assert_tsd_data_cleanup_done(tsd_t * tsd)88*1208bc7eSAndroid Build Coastguard Worker assert_tsd_data_cleanup_done(tsd_t *tsd) {
89*1208bc7eSAndroid Build Coastguard Worker assert(!tsd_nominal(tsd));
90*1208bc7eSAndroid Build Coastguard Worker assert(*tsd_arenap_get_unsafe(tsd) == NULL);
91*1208bc7eSAndroid Build Coastguard Worker assert(*tsd_iarenap_get_unsafe(tsd) == NULL);
92*1208bc7eSAndroid Build Coastguard Worker assert(*tsd_arenas_tdata_bypassp_get_unsafe(tsd) == true);
93*1208bc7eSAndroid Build Coastguard Worker assert(*tsd_arenas_tdatap_get_unsafe(tsd) == NULL);
94*1208bc7eSAndroid Build Coastguard Worker assert(*tsd_tcache_enabledp_get_unsafe(tsd) == false);
95*1208bc7eSAndroid Build Coastguard Worker assert(*tsd_prof_tdatap_get_unsafe(tsd) == NULL);
96*1208bc7eSAndroid Build Coastguard Worker }
97*1208bc7eSAndroid Build Coastguard Worker
98*1208bc7eSAndroid Build Coastguard Worker static bool
tsd_data_init_nocleanup(tsd_t * tsd)99*1208bc7eSAndroid Build Coastguard Worker tsd_data_init_nocleanup(tsd_t *tsd) {
100*1208bc7eSAndroid Build Coastguard Worker assert(tsd->state == tsd_state_reincarnated ||
101*1208bc7eSAndroid Build Coastguard Worker tsd->state == tsd_state_minimal_initialized);
102*1208bc7eSAndroid Build Coastguard Worker /*
103*1208bc7eSAndroid Build Coastguard Worker * During reincarnation, there is no guarantee that the cleanup function
104*1208bc7eSAndroid Build Coastguard Worker * will be called (deallocation may happen after all tsd destructors).
105*1208bc7eSAndroid Build Coastguard Worker * We set up tsd in a way that no cleanup is needed.
106*1208bc7eSAndroid Build Coastguard Worker */
107*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd));
108*1208bc7eSAndroid Build Coastguard Worker *tsd_arenas_tdata_bypassp_get(tsd) = true;
109*1208bc7eSAndroid Build Coastguard Worker *tsd_tcache_enabledp_get_unsafe(tsd) = false;
110*1208bc7eSAndroid Build Coastguard Worker *tsd_reentrancy_levelp_get(tsd) = 1;
111*1208bc7eSAndroid Build Coastguard Worker assert_tsd_data_cleanup_done(tsd);
112*1208bc7eSAndroid Build Coastguard Worker
113*1208bc7eSAndroid Build Coastguard Worker return false;
114*1208bc7eSAndroid Build Coastguard Worker }
115*1208bc7eSAndroid Build Coastguard Worker
116*1208bc7eSAndroid Build Coastguard Worker tsd_t *
tsd_fetch_slow(tsd_t * tsd,bool minimal)117*1208bc7eSAndroid Build Coastguard Worker tsd_fetch_slow(tsd_t *tsd, bool minimal) {
118*1208bc7eSAndroid Build Coastguard Worker assert(!tsd_fast(tsd));
119*1208bc7eSAndroid Build Coastguard Worker
120*1208bc7eSAndroid Build Coastguard Worker if (tsd->state == tsd_state_nominal_slow) {
121*1208bc7eSAndroid Build Coastguard Worker /* On slow path but no work needed. */
122*1208bc7eSAndroid Build Coastguard Worker assert(malloc_slow || !tsd_tcache_enabled_get(tsd) ||
123*1208bc7eSAndroid Build Coastguard Worker tsd_reentrancy_level_get(tsd) > 0 ||
124*1208bc7eSAndroid Build Coastguard Worker *tsd_arenas_tdata_bypassp_get(tsd));
125*1208bc7eSAndroid Build Coastguard Worker } else if (tsd->state == tsd_state_uninitialized) {
126*1208bc7eSAndroid Build Coastguard Worker if (!minimal) {
127*1208bc7eSAndroid Build Coastguard Worker tsd->state = tsd_state_nominal;
128*1208bc7eSAndroid Build Coastguard Worker tsd_slow_update(tsd);
129*1208bc7eSAndroid Build Coastguard Worker /* Trigger cleanup handler registration. */
130*1208bc7eSAndroid Build Coastguard Worker tsd_set(tsd);
131*1208bc7eSAndroid Build Coastguard Worker tsd_data_init(tsd);
132*1208bc7eSAndroid Build Coastguard Worker } else {
133*1208bc7eSAndroid Build Coastguard Worker tsd->state = tsd_state_minimal_initialized;
134*1208bc7eSAndroid Build Coastguard Worker tsd_set(tsd);
135*1208bc7eSAndroid Build Coastguard Worker tsd_data_init_nocleanup(tsd);
136*1208bc7eSAndroid Build Coastguard Worker }
137*1208bc7eSAndroid Build Coastguard Worker } else if (tsd->state == tsd_state_minimal_initialized) {
138*1208bc7eSAndroid Build Coastguard Worker if (!minimal) {
139*1208bc7eSAndroid Build Coastguard Worker /* Switch to fully initialized. */
140*1208bc7eSAndroid Build Coastguard Worker tsd->state = tsd_state_nominal;
141*1208bc7eSAndroid Build Coastguard Worker assert(*tsd_reentrancy_levelp_get(tsd) >= 1);
142*1208bc7eSAndroid Build Coastguard Worker (*tsd_reentrancy_levelp_get(tsd))--;
143*1208bc7eSAndroid Build Coastguard Worker tsd_slow_update(tsd);
144*1208bc7eSAndroid Build Coastguard Worker tsd_data_init(tsd);
145*1208bc7eSAndroid Build Coastguard Worker } else {
146*1208bc7eSAndroid Build Coastguard Worker assert_tsd_data_cleanup_done(tsd);
147*1208bc7eSAndroid Build Coastguard Worker }
148*1208bc7eSAndroid Build Coastguard Worker } else if (tsd->state == tsd_state_purgatory) {
149*1208bc7eSAndroid Build Coastguard Worker tsd->state = tsd_state_reincarnated;
150*1208bc7eSAndroid Build Coastguard Worker tsd_set(tsd);
151*1208bc7eSAndroid Build Coastguard Worker tsd_data_init_nocleanup(tsd);
152*1208bc7eSAndroid Build Coastguard Worker } else {
153*1208bc7eSAndroid Build Coastguard Worker assert(tsd->state == tsd_state_reincarnated);
154*1208bc7eSAndroid Build Coastguard Worker }
155*1208bc7eSAndroid Build Coastguard Worker
156*1208bc7eSAndroid Build Coastguard Worker return tsd;
157*1208bc7eSAndroid Build Coastguard Worker }
158*1208bc7eSAndroid Build Coastguard Worker
159*1208bc7eSAndroid Build Coastguard Worker void *
malloc_tsd_malloc(size_t size)160*1208bc7eSAndroid Build Coastguard Worker malloc_tsd_malloc(size_t size) {
161*1208bc7eSAndroid Build Coastguard Worker return a0malloc(CACHELINE_CEILING(size));
162*1208bc7eSAndroid Build Coastguard Worker }
163*1208bc7eSAndroid Build Coastguard Worker
164*1208bc7eSAndroid Build Coastguard Worker void
malloc_tsd_dalloc(void * wrapper)165*1208bc7eSAndroid Build Coastguard Worker malloc_tsd_dalloc(void *wrapper) {
166*1208bc7eSAndroid Build Coastguard Worker a0dalloc(wrapper);
167*1208bc7eSAndroid Build Coastguard Worker }
168*1208bc7eSAndroid Build Coastguard Worker
169*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
170*1208bc7eSAndroid Build Coastguard Worker #ifndef _WIN32
171*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT
172*1208bc7eSAndroid Build Coastguard Worker #endif
173*1208bc7eSAndroid Build Coastguard Worker void
_malloc_thread_cleanup(void)174*1208bc7eSAndroid Build Coastguard Worker _malloc_thread_cleanup(void) {
175*1208bc7eSAndroid Build Coastguard Worker bool pending[MALLOC_TSD_CLEANUPS_MAX], again;
176*1208bc7eSAndroid Build Coastguard Worker unsigned i;
177*1208bc7eSAndroid Build Coastguard Worker
178*1208bc7eSAndroid Build Coastguard Worker for (i = 0; i < ncleanups; i++) {
179*1208bc7eSAndroid Build Coastguard Worker pending[i] = true;
180*1208bc7eSAndroid Build Coastguard Worker }
181*1208bc7eSAndroid Build Coastguard Worker
182*1208bc7eSAndroid Build Coastguard Worker do {
183*1208bc7eSAndroid Build Coastguard Worker again = false;
184*1208bc7eSAndroid Build Coastguard Worker for (i = 0; i < ncleanups; i++) {
185*1208bc7eSAndroid Build Coastguard Worker if (pending[i]) {
186*1208bc7eSAndroid Build Coastguard Worker pending[i] = cleanups[i]();
187*1208bc7eSAndroid Build Coastguard Worker if (pending[i]) {
188*1208bc7eSAndroid Build Coastguard Worker again = true;
189*1208bc7eSAndroid Build Coastguard Worker }
190*1208bc7eSAndroid Build Coastguard Worker }
191*1208bc7eSAndroid Build Coastguard Worker }
192*1208bc7eSAndroid Build Coastguard Worker } while (again);
193*1208bc7eSAndroid Build Coastguard Worker }
194*1208bc7eSAndroid Build Coastguard Worker #endif
195*1208bc7eSAndroid Build Coastguard Worker
196*1208bc7eSAndroid Build Coastguard Worker void
malloc_tsd_cleanup_register(bool (* f)(void))197*1208bc7eSAndroid Build Coastguard Worker malloc_tsd_cleanup_register(bool (*f)(void)) {
198*1208bc7eSAndroid Build Coastguard Worker assert(ncleanups < MALLOC_TSD_CLEANUPS_MAX);
199*1208bc7eSAndroid Build Coastguard Worker cleanups[ncleanups] = f;
200*1208bc7eSAndroid Build Coastguard Worker ncleanups++;
201*1208bc7eSAndroid Build Coastguard Worker }
202*1208bc7eSAndroid Build Coastguard Worker
203*1208bc7eSAndroid Build Coastguard Worker static void
tsd_do_data_cleanup(tsd_t * tsd)204*1208bc7eSAndroid Build Coastguard Worker tsd_do_data_cleanup(tsd_t *tsd) {
205*1208bc7eSAndroid Build Coastguard Worker prof_tdata_cleanup(tsd);
206*1208bc7eSAndroid Build Coastguard Worker iarena_cleanup(tsd);
207*1208bc7eSAndroid Build Coastguard Worker arena_cleanup(tsd);
208*1208bc7eSAndroid Build Coastguard Worker arenas_tdata_cleanup(tsd);
209*1208bc7eSAndroid Build Coastguard Worker tcache_cleanup(tsd);
210*1208bc7eSAndroid Build Coastguard Worker witnesses_cleanup(tsd_witness_tsdp_get_unsafe(tsd));
211*1208bc7eSAndroid Build Coastguard Worker }
212*1208bc7eSAndroid Build Coastguard Worker
213*1208bc7eSAndroid Build Coastguard Worker void
tsd_cleanup(void * arg)214*1208bc7eSAndroid Build Coastguard Worker tsd_cleanup(void *arg) {
215*1208bc7eSAndroid Build Coastguard Worker tsd_t *tsd = (tsd_t *)arg;
216*1208bc7eSAndroid Build Coastguard Worker
217*1208bc7eSAndroid Build Coastguard Worker switch (tsd->state) {
218*1208bc7eSAndroid Build Coastguard Worker case tsd_state_uninitialized:
219*1208bc7eSAndroid Build Coastguard Worker /* Do nothing. */
220*1208bc7eSAndroid Build Coastguard Worker break;
221*1208bc7eSAndroid Build Coastguard Worker case tsd_state_minimal_initialized:
222*1208bc7eSAndroid Build Coastguard Worker /* This implies the thread only did free() in its life time. */
223*1208bc7eSAndroid Build Coastguard Worker /* Fall through. */
224*1208bc7eSAndroid Build Coastguard Worker case tsd_state_reincarnated:
225*1208bc7eSAndroid Build Coastguard Worker /*
226*1208bc7eSAndroid Build Coastguard Worker * Reincarnated means another destructor deallocated memory
227*1208bc7eSAndroid Build Coastguard Worker * after the destructor was called. Cleanup isn't required but
228*1208bc7eSAndroid Build Coastguard Worker * is still called for testing and completeness.
229*1208bc7eSAndroid Build Coastguard Worker */
230*1208bc7eSAndroid Build Coastguard Worker assert_tsd_data_cleanup_done(tsd);
231*1208bc7eSAndroid Build Coastguard Worker /* Fall through. */
232*1208bc7eSAndroid Build Coastguard Worker case tsd_state_nominal:
233*1208bc7eSAndroid Build Coastguard Worker case tsd_state_nominal_slow:
234*1208bc7eSAndroid Build Coastguard Worker tsd_do_data_cleanup(tsd);
235*1208bc7eSAndroid Build Coastguard Worker tsd->state = tsd_state_purgatory;
236*1208bc7eSAndroid Build Coastguard Worker tsd_set(tsd);
237*1208bc7eSAndroid Build Coastguard Worker break;
238*1208bc7eSAndroid Build Coastguard Worker case tsd_state_purgatory:
239*1208bc7eSAndroid Build Coastguard Worker /*
240*1208bc7eSAndroid Build Coastguard Worker * The previous time this destructor was called, we set the
241*1208bc7eSAndroid Build Coastguard Worker * state to tsd_state_purgatory so that other destructors
242*1208bc7eSAndroid Build Coastguard Worker * wouldn't cause re-creation of the tsd. This time, do
243*1208bc7eSAndroid Build Coastguard Worker * nothing, and do not request another callback.
244*1208bc7eSAndroid Build Coastguard Worker */
245*1208bc7eSAndroid Build Coastguard Worker break;
246*1208bc7eSAndroid Build Coastguard Worker default:
247*1208bc7eSAndroid Build Coastguard Worker not_reached();
248*1208bc7eSAndroid Build Coastguard Worker }
249*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_JET
250*1208bc7eSAndroid Build Coastguard Worker test_callback_t test_callback = *tsd_test_callbackp_get_unsafe(tsd);
251*1208bc7eSAndroid Build Coastguard Worker int *data = tsd_test_datap_get_unsafe(tsd);
252*1208bc7eSAndroid Build Coastguard Worker if (test_callback != NULL) {
253*1208bc7eSAndroid Build Coastguard Worker test_callback(data);
254*1208bc7eSAndroid Build Coastguard Worker }
255*1208bc7eSAndroid Build Coastguard Worker #endif
256*1208bc7eSAndroid Build Coastguard Worker }
257*1208bc7eSAndroid Build Coastguard Worker
258*1208bc7eSAndroid Build Coastguard Worker tsd_t *
malloc_tsd_boot0(void)259*1208bc7eSAndroid Build Coastguard Worker malloc_tsd_boot0(void) {
260*1208bc7eSAndroid Build Coastguard Worker tsd_t *tsd;
261*1208bc7eSAndroid Build Coastguard Worker
262*1208bc7eSAndroid Build Coastguard Worker ncleanups = 0;
263*1208bc7eSAndroid Build Coastguard Worker if (tsd_boot0()) {
264*1208bc7eSAndroid Build Coastguard Worker return NULL;
265*1208bc7eSAndroid Build Coastguard Worker }
266*1208bc7eSAndroid Build Coastguard Worker tsd = tsd_fetch();
267*1208bc7eSAndroid Build Coastguard Worker *tsd_arenas_tdata_bypassp_get(tsd) = true;
268*1208bc7eSAndroid Build Coastguard Worker return tsd;
269*1208bc7eSAndroid Build Coastguard Worker }
270*1208bc7eSAndroid Build Coastguard Worker
271*1208bc7eSAndroid Build Coastguard Worker void
malloc_tsd_boot1(void)272*1208bc7eSAndroid Build Coastguard Worker malloc_tsd_boot1(void) {
273*1208bc7eSAndroid Build Coastguard Worker tsd_boot1();
274*1208bc7eSAndroid Build Coastguard Worker tsd_t *tsd = tsd_fetch();
275*1208bc7eSAndroid Build Coastguard Worker /* malloc_slow has been set properly. Update tsd_slow. */
276*1208bc7eSAndroid Build Coastguard Worker tsd_slow_update(tsd);
277*1208bc7eSAndroid Build Coastguard Worker *tsd_arenas_tdata_bypassp_get(tsd) = false;
278*1208bc7eSAndroid Build Coastguard Worker }
279*1208bc7eSAndroid Build Coastguard Worker
280*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
281*1208bc7eSAndroid Build Coastguard Worker static BOOL WINAPI
_tls_callback(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)282*1208bc7eSAndroid Build Coastguard Worker _tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
283*1208bc7eSAndroid Build Coastguard Worker switch (fdwReason) {
284*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_LAZY_LOCK
285*1208bc7eSAndroid Build Coastguard Worker case DLL_THREAD_ATTACH:
286*1208bc7eSAndroid Build Coastguard Worker isthreaded = true;
287*1208bc7eSAndroid Build Coastguard Worker break;
288*1208bc7eSAndroid Build Coastguard Worker #endif
289*1208bc7eSAndroid Build Coastguard Worker case DLL_THREAD_DETACH:
290*1208bc7eSAndroid Build Coastguard Worker _malloc_thread_cleanup();
291*1208bc7eSAndroid Build Coastguard Worker break;
292*1208bc7eSAndroid Build Coastguard Worker default:
293*1208bc7eSAndroid Build Coastguard Worker break;
294*1208bc7eSAndroid Build Coastguard Worker }
295*1208bc7eSAndroid Build Coastguard Worker return true;
296*1208bc7eSAndroid Build Coastguard Worker }
297*1208bc7eSAndroid Build Coastguard Worker
298*1208bc7eSAndroid Build Coastguard Worker /*
299*1208bc7eSAndroid Build Coastguard Worker * We need to be able to say "read" here (in the "pragma section"), but have
300*1208bc7eSAndroid Build Coastguard Worker * hooked "read". We won't read for the rest of the file, so we can get away
301*1208bc7eSAndroid Build Coastguard Worker * with unhooking.
302*1208bc7eSAndroid Build Coastguard Worker */
303*1208bc7eSAndroid Build Coastguard Worker #ifdef read
304*1208bc7eSAndroid Build Coastguard Worker # undef read
305*1208bc7eSAndroid Build Coastguard Worker #endif
306*1208bc7eSAndroid Build Coastguard Worker
307*1208bc7eSAndroid Build Coastguard Worker #ifdef _MSC_VER
308*1208bc7eSAndroid Build Coastguard Worker # ifdef _M_IX86
309*1208bc7eSAndroid Build Coastguard Worker # pragma comment(linker, "/INCLUDE:__tls_used")
310*1208bc7eSAndroid Build Coastguard Worker # pragma comment(linker, "/INCLUDE:_tls_callback")
311*1208bc7eSAndroid Build Coastguard Worker # else
312*1208bc7eSAndroid Build Coastguard Worker # pragma comment(linker, "/INCLUDE:_tls_used")
313*1208bc7eSAndroid Build Coastguard Worker # pragma comment(linker, "/INCLUDE:tls_callback")
314*1208bc7eSAndroid Build Coastguard Worker # endif
315*1208bc7eSAndroid Build Coastguard Worker # pragma section(".CRT$XLY",long,read)
316*1208bc7eSAndroid Build Coastguard Worker #endif
317*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_SECTION(".CRT$XLY") JEMALLOC_ATTR(used)
318*1208bc7eSAndroid Build Coastguard Worker BOOL (WINAPI *const tls_callback)(HINSTANCE hinstDLL,
319*1208bc7eSAndroid Build Coastguard Worker DWORD fdwReason, LPVOID lpvReserved) = _tls_callback;
320*1208bc7eSAndroid Build Coastguard Worker #endif
321*1208bc7eSAndroid Build Coastguard Worker
322*1208bc7eSAndroid Build Coastguard Worker #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
323*1208bc7eSAndroid Build Coastguard Worker !defined(_WIN32))
324*1208bc7eSAndroid Build Coastguard Worker void *
tsd_init_check_recursion(tsd_init_head_t * head,tsd_init_block_t * block)325*1208bc7eSAndroid Build Coastguard Worker tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) {
326*1208bc7eSAndroid Build Coastguard Worker pthread_t self = pthread_self();
327*1208bc7eSAndroid Build Coastguard Worker tsd_init_block_t *iter;
328*1208bc7eSAndroid Build Coastguard Worker
329*1208bc7eSAndroid Build Coastguard Worker /* Check whether this thread has already inserted into the list. */
330*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(TSDN_NULL, &head->lock);
331*1208bc7eSAndroid Build Coastguard Worker ql_foreach(iter, &head->blocks, link) {
332*1208bc7eSAndroid Build Coastguard Worker if (iter->thread == self) {
333*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(TSDN_NULL, &head->lock);
334*1208bc7eSAndroid Build Coastguard Worker return iter->data;
335*1208bc7eSAndroid Build Coastguard Worker }
336*1208bc7eSAndroid Build Coastguard Worker }
337*1208bc7eSAndroid Build Coastguard Worker /* Insert block into list. */
338*1208bc7eSAndroid Build Coastguard Worker ql_elm_new(block, link);
339*1208bc7eSAndroid Build Coastguard Worker block->thread = self;
340*1208bc7eSAndroid Build Coastguard Worker ql_tail_insert(&head->blocks, block, link);
341*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(TSDN_NULL, &head->lock);
342*1208bc7eSAndroid Build Coastguard Worker return NULL;
343*1208bc7eSAndroid Build Coastguard Worker }
344*1208bc7eSAndroid Build Coastguard Worker
345*1208bc7eSAndroid Build Coastguard Worker void
tsd_init_finish(tsd_init_head_t * head,tsd_init_block_t * block)346*1208bc7eSAndroid Build Coastguard Worker tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block) {
347*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(TSDN_NULL, &head->lock);
348*1208bc7eSAndroid Build Coastguard Worker ql_remove(&head->blocks, block, link);
349*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(TSDN_NULL, &head->lock);
350*1208bc7eSAndroid Build Coastguard Worker }
351*1208bc7eSAndroid Build Coastguard Worker #endif
352