1#define	JEMALLOC_TSD_C_
2#include "jemalloc/internal/jemalloc_internal.h"
3
4/******************************************************************************/
5/* Data. */
6
7static unsigned ncleanups;
8static malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX];
9
10malloc_tsd_data(, , tsd_t, TSD_INITIALIZER)
11
12/******************************************************************************/
13
14void *
15malloc_tsd_malloc(size_t size)
16{
17	return (a0malloc(CACHELINE_CEILING(size)));
18}
19
20void
21malloc_tsd_dalloc(void *wrapper)
22{
23	a0dalloc(wrapper);
24}
25
26void
27malloc_tsd_no_cleanup(void *arg)
28{
29	not_reached();
30}
31
32#if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
33#ifndef _WIN32
34JEMALLOC_EXPORT
35#endif
36void
37_malloc_thread_cleanup(void)
38{
39	bool pending[MALLOC_TSD_CLEANUPS_MAX], again;
40	unsigned i;
41
42	for (i = 0; i < ncleanups; i++)
43		pending[i] = true;
44
45	do {
46		again = false;
47		for (i = 0; i < ncleanups; i++) {
48			if (pending[i]) {
49				pending[i] = cleanups[i]();
50				if (pending[i])
51					again = true;
52			}
53		}
54	} while (again);
55}
56#endif
57
58void
59malloc_tsd_cleanup_register(bool (*f)(void))
60{
61	assert(ncleanups < MALLOC_TSD_CLEANUPS_MAX);
62	cleanups[ncleanups] = f;
63	ncleanups++;
64}
65
66void
67tsd_cleanup(void *arg)
68{
69	tsd_t *tsd = (tsd_t *)arg;
70
71	switch (tsd->state) {
72	case tsd_state_uninitialized:
73		/* Do nothing. */
74		break;
75	case tsd_state_nominal:
76#define	MALLOC_TSD_cleanup_yes(n, t)					\
77		n##_cleanup(tsd);
78#define	MALLOC_TSD_cleanup_no(n, t)
79#define	O(n, t, c)							\
80		MALLOC_TSD_cleanup_##c(n, t)
81MALLOC_TSD
82#undef MALLOC_TSD_cleanup_yes
83#undef MALLOC_TSD_cleanup_no
84#undef O
85		tsd->state = tsd_state_purgatory;
86		tsd_set(tsd);
87		break;
88	case tsd_state_purgatory:
89		/*
90		 * The previous time this destructor was called, we set the
91		 * state to tsd_state_purgatory so that other destructors
92		 * wouldn't cause re-creation of the tsd.  This time, do
93		 * nothing, and do not request another callback.
94		 */
95		break;
96	case tsd_state_reincarnated:
97		/*
98		 * Another destructor deallocated memory after this destructor
99		 * was called.  Reset state to tsd_state_purgatory and request
100		 * another callback.
101		 */
102		tsd->state = tsd_state_purgatory;
103		tsd_set(tsd);
104		break;
105	default:
106		not_reached();
107	}
108}
109
110tsd_t *
111malloc_tsd_boot0(void)
112{
113	tsd_t *tsd;
114
115	ncleanups = 0;
116	if (tsd_boot0())
117		return (NULL);
118	tsd = tsd_fetch();
119	*tsd_arenas_tdata_bypassp_get(tsd) = true;
120	return (tsd);
121}
122
123void
124malloc_tsd_boot1(void)
125{
126	tsd_boot1();
127	*tsd_arenas_tdata_bypassp_get(tsd_fetch()) = false;
128}
129
130#ifdef _WIN32
131static BOOL WINAPI
132_tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
133{
134	switch (fdwReason) {
135#ifdef JEMALLOC_LAZY_LOCK
136	case DLL_THREAD_ATTACH:
137		isthreaded = true;
138		break;
139#endif
140	case DLL_THREAD_DETACH:
141		_malloc_thread_cleanup();
142		break;
143	default:
144		break;
145	}
146	return (true);
147}
148
149#ifdef _MSC_VER
150#  ifdef _M_IX86
151#    pragma comment(linker, "/INCLUDE:__tls_used")
152#    pragma comment(linker, "/INCLUDE:_tls_callback")
153#  else
154#    pragma comment(linker, "/INCLUDE:_tls_used")
155#    pragma comment(linker, "/INCLUDE:tls_callback")
156#  endif
157#  pragma section(".CRT$XLY",long,read)
158#endif
159JEMALLOC_SECTION(".CRT$XLY") JEMALLOC_ATTR(used)
160BOOL	(WINAPI *const tls_callback)(HINSTANCE hinstDLL,
161    DWORD fdwReason, LPVOID lpvReserved) = _tls_callback;
162#endif
163
164#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
165    !defined(_WIN32))
166void *
167tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block)
168{
169	pthread_t self = pthread_self();
170	tsd_init_block_t *iter;
171
172	/* Check whether this thread has already inserted into the list. */
173	malloc_mutex_lock(TSDN_NULL, &head->lock);
174	ql_foreach(iter, &head->blocks, link) {
175		if (iter->thread == self) {
176			malloc_mutex_unlock(TSDN_NULL, &head->lock);
177			return (iter->data);
178		}
179	}
180	/* Insert block into list. */
181	ql_elm_new(block, link);
182	block->thread = self;
183	ql_tail_insert(&head->blocks, block, link);
184	malloc_mutex_unlock(TSDN_NULL, &head->lock);
185	return (NULL);
186}
187
188void
189tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block)
190{
191	malloc_mutex_lock(TSDN_NULL, &head->lock);
192	ql_remove(&head->blocks, block, link);
193	malloc_mutex_unlock(TSDN_NULL, &head->lock);
194}
195#endif
196