1234370Sjasone#define	JEMALLOC_TSD_C_
2234370Sjasone#include "jemalloc/internal/jemalloc_internal.h"
3234370Sjasone
4234370Sjasone/******************************************************************************/
5234370Sjasone/* Data. */
6234370Sjasone
7234370Sjasonestatic unsigned ncleanups;
8234370Sjasonestatic malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX];
9234370Sjasone
10286866Sjasonemalloc_tsd_data(, , tsd_t, TSD_INITIALIZER)
11286866Sjasone
12234370Sjasone/******************************************************************************/
13234370Sjasone
14234370Sjasonevoid *
15234370Sjasonemalloc_tsd_malloc(size_t size)
16234370Sjasone{
17234370Sjasone
18286866Sjasone	return (a0malloc(CACHELINE_CEILING(size)));
19234370Sjasone}
20234370Sjasone
21234370Sjasonevoid
22234370Sjasonemalloc_tsd_dalloc(void *wrapper)
23234370Sjasone{
24234370Sjasone
25286866Sjasone	a0dalloc(wrapper);
26234370Sjasone}
27234370Sjasone
28234370Sjasonevoid
29234370Sjasonemalloc_tsd_no_cleanup(void *arg)
30234370Sjasone{
31234370Sjasone
32234370Sjasone	not_reached();
33234370Sjasone}
34234370Sjasone
35235238Sjasone#if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
36235238Sjasone#ifndef _WIN32
37235238SjasoneJEMALLOC_EXPORT
38235238Sjasone#endif
39234370Sjasonevoid
40234370Sjasone_malloc_thread_cleanup(void)
41234370Sjasone{
42235238Sjasone	bool pending[MALLOC_TSD_CLEANUPS_MAX], again;
43234370Sjasone	unsigned i;
44234370Sjasone
45234370Sjasone	for (i = 0; i < ncleanups; i++)
46234370Sjasone		pending[i] = true;
47234370Sjasone
48234370Sjasone	do {
49234370Sjasone		again = false;
50234370Sjasone		for (i = 0; i < ncleanups; i++) {
51234370Sjasone			if (pending[i]) {
52234543Sjasone				pending[i] = cleanups[i]();
53234370Sjasone				if (pending[i])
54234370Sjasone					again = true;
55234370Sjasone			}
56234370Sjasone		}
57234370Sjasone	} while (again);
58234370Sjasone}
59234370Sjasone#endif
60234370Sjasone
61234370Sjasonevoid
62234543Sjasonemalloc_tsd_cleanup_register(bool (*f)(void))
63234370Sjasone{
64234370Sjasone
65234370Sjasone	assert(ncleanups < MALLOC_TSD_CLEANUPS_MAX);
66234543Sjasone	cleanups[ncleanups] = f;
67234370Sjasone	ncleanups++;
68234370Sjasone}
69234370Sjasone
70234370Sjasonevoid
71286866Sjasonetsd_cleanup(void *arg)
72234370Sjasone{
73286866Sjasone	tsd_t *tsd = (tsd_t *)arg;
74234370Sjasone
75286866Sjasone	switch (tsd->state) {
76289900Sjasone	case tsd_state_uninitialized:
77289900Sjasone		/* Do nothing. */
78289900Sjasone		break;
79286866Sjasone	case tsd_state_nominal:
80299587Sjasone#define	O(n, t)								\
81286866Sjasone		n##_cleanup(tsd);
82286866SjasoneMALLOC_TSD
83286866Sjasone#undef O
84286866Sjasone		tsd->state = tsd_state_purgatory;
85286866Sjasone		tsd_set(tsd);
86286866Sjasone		break;
87286866Sjasone	case tsd_state_purgatory:
88286866Sjasone		/*
89286866Sjasone		 * The previous time this destructor was called, we set the
90286866Sjasone		 * state to tsd_state_purgatory so that other destructors
91286866Sjasone		 * wouldn't cause re-creation of the tsd.  This time, do
92286866Sjasone		 * nothing, and do not request another callback.
93286866Sjasone		 */
94286866Sjasone		break;
95286866Sjasone	case tsd_state_reincarnated:
96286866Sjasone		/*
97286866Sjasone		 * Another destructor deallocated memory after this destructor
98286866Sjasone		 * was called.  Reset state to tsd_state_purgatory and request
99286866Sjasone		 * another callback.
100286866Sjasone		 */
101286866Sjasone		tsd->state = tsd_state_purgatory;
102286866Sjasone		tsd_set(tsd);
103286866Sjasone		break;
104286866Sjasone	default:
105286866Sjasone		not_reached();
106286866Sjasone	}
107286866Sjasone}
108286866Sjasone
109299587Sjasonetsd_t *
110286866Sjasonemalloc_tsd_boot0(void)
111286866Sjasone{
112299587Sjasone	tsd_t *tsd;
113286866Sjasone
114234370Sjasone	ncleanups = 0;
115286866Sjasone	if (tsd_boot0())
116299587Sjasone		return (NULL);
117299587Sjasone	tsd = tsd_fetch();
118299587Sjasone	*tsd_arenas_tdata_bypassp_get(tsd) = true;
119299587Sjasone	return (tsd);
120234370Sjasone}
121235238Sjasone
122286866Sjasonevoid
123286866Sjasonemalloc_tsd_boot1(void)
124286866Sjasone{
125286866Sjasone
126286866Sjasone	tsd_boot1();
127296221Sjasone	*tsd_arenas_tdata_bypassp_get(tsd_fetch()) = false;
128286866Sjasone}
129286866Sjasone
130235238Sjasone#ifdef _WIN32
131235238Sjasonestatic BOOL WINAPI
132235238Sjasone_tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
133235238Sjasone{
134235238Sjasone
135235238Sjasone	switch (fdwReason) {
136235238Sjasone#ifdef JEMALLOC_LAZY_LOCK
137235238Sjasone	case DLL_THREAD_ATTACH:
138235238Sjasone		isthreaded = true;
139235238Sjasone		break;
140235238Sjasone#endif
141235238Sjasone	case DLL_THREAD_DETACH:
142235238Sjasone		_malloc_thread_cleanup();
143235238Sjasone		break;
144235238Sjasone	default:
145235238Sjasone		break;
146235238Sjasone	}
147235238Sjasone	return (true);
148235238Sjasone}
149235238Sjasone
150235238Sjasone#ifdef _MSC_VER
151235238Sjasone#  ifdef _M_IX86
152235238Sjasone#    pragma comment(linker, "/INCLUDE:__tls_used")
153296221Sjasone#    pragma comment(linker, "/INCLUDE:_tls_callback")
154235238Sjasone#  else
155235238Sjasone#    pragma comment(linker, "/INCLUDE:_tls_used")
156296221Sjasone#    pragma comment(linker, "/INCLUDE:tls_callback")
157235238Sjasone#  endif
158235238Sjasone#  pragma section(".CRT$XLY",long,read)
159235238Sjasone#endif
160235238SjasoneJEMALLOC_SECTION(".CRT$XLY") JEMALLOC_ATTR(used)
161296221SjasoneBOOL	(WINAPI *const tls_callback)(HINSTANCE hinstDLL,
162235238Sjasone    DWORD fdwReason, LPVOID lpvReserved) = _tls_callback;
163235238Sjasone#endif
164261071Sjasone
165261071Sjasone#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
166261071Sjasone    !defined(_WIN32))
167261071Sjasonevoid *
168261071Sjasonetsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block)
169261071Sjasone{
170261071Sjasone	pthread_t self = pthread_self();
171261071Sjasone	tsd_init_block_t *iter;
172261071Sjasone
173261071Sjasone	/* Check whether this thread has already inserted into the list. */
174299587Sjasone	malloc_mutex_lock(NULL, &head->lock);
175261071Sjasone	ql_foreach(iter, &head->blocks, link) {
176261071Sjasone		if (iter->thread == self) {
177299587Sjasone			malloc_mutex_unlock(NULL, &head->lock);
178261071Sjasone			return (iter->data);
179261071Sjasone		}
180261071Sjasone	}
181261071Sjasone	/* Insert block into list. */
182261071Sjasone	ql_elm_new(block, link);
183261071Sjasone	block->thread = self;
184261071Sjasone	ql_tail_insert(&head->blocks, block, link);
185299587Sjasone	malloc_mutex_unlock(NULL, &head->lock);
186261071Sjasone	return (NULL);
187261071Sjasone}
188261071Sjasone
189261071Sjasonevoid
190261071Sjasonetsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block)
191261071Sjasone{
192261071Sjasone
193299587Sjasone	malloc_mutex_lock(NULL, &head->lock);
194261071Sjasone	ql_remove(&head->blocks, block, link);
195299587Sjasone	malloc_mutex_unlock(NULL, &head->lock);
196261071Sjasone}
197261071Sjasone#endif
198