1 /******************************************************************************/
2 #ifdef JEMALLOC_H_TYPES
4 /* Maximum number of malloc_tsd users with cleanup functions. */
5 #define MALLOC_TSD_CLEANUPS_MAX 8
7 typedef bool (*malloc_tsd_cleanup_t)(void);
10 * TLS/TSD-agnostic macro-based implementation of thread-specific data. There
11 * are four macros that support (at least) three use cases: file-private,
12 * library-private, and library-private inlined. Following is an example
13 * library-private tsd variable:
20 * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0})
21 * malloc_tsd_protos(, example, example_t *)
22 * malloc_tsd_externs(example, example_t *)
24 * malloc_tsd_data(, example, example_t *, EX_INITIALIZER)
25 * malloc_tsd_funcs(, example, example_t *, EX_INITIALIZER,
26 * example_tsd_cleanup)
28 * The result is a set of generated functions, e.g.:
30 * bool example_tsd_boot(void) {...}
31 * example_t **example_tsd_get() {...}
32 * void example_tsd_set(example_t **val) {...}
34 * Note that all of the functions deal in terms of (a_type *) rather than
35 * (a_type) so that it is possible to support non-pointer types (unlike
36 * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is
37 * cast to (void *). This means that the cleanup function needs to cast *and*
38 * dereference the function argument, e.g.:
41 * example_tsd_cleanup(void *arg)
43 * example_t *example = *(example_t **)arg;
46 * if ([want the cleanup function to be called again]) {
47 * example_tsd_set(&example);
51 * If example_tsd_set() is called within example_tsd_cleanup(), it will be
52 * called again. This is similar to how pthreads TSD destruction works, except
53 * that pthreads only calls the cleanup function again if the value was set to
57 /* malloc_tsd_protos(). */
58 #define malloc_tsd_protos(a_attr, a_name, a_type) \
60 a_name##_tsd_boot(void); \
62 a_name##_tsd_get(void); \
64 a_name##_tsd_set(a_type *val);
66 /* malloc_tsd_externs(). */
67 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
68 #define malloc_tsd_externs(a_name, a_type) \
69 extern __thread a_type a_name##_tls; \
70 extern __thread bool a_name##_initialized; \
71 extern bool a_name##_booted;
72 #elif (defined(JEMALLOC_TLS))
73 #define malloc_tsd_externs(a_name, a_type) \
74 extern __thread a_type a_name##_tls; \
75 extern pthread_key_t a_name##_tsd; \
76 extern bool a_name##_booted;
77 #elif (defined(_WIN32))
78 #define malloc_tsd_externs(a_name, a_type) \
79 extern DWORD a_name##_tsd; \
80 extern bool a_name##_booted;
82 #define malloc_tsd_externs(a_name, a_type) \
83 extern pthread_key_t a_name##_tsd; \
84 extern bool a_name##_booted;
87 /* malloc_tsd_data(). */
88 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
89 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
90 a_attr __thread a_type JEMALLOC_TLS_MODEL \
91 a_name##_tls = a_initializer; \
92 a_attr __thread bool JEMALLOC_TLS_MODEL \
93 a_name##_initialized = false; \
94 a_attr bool a_name##_booted = false;
95 #elif (defined(JEMALLOC_TLS))
96 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
97 a_attr __thread a_type JEMALLOC_TLS_MODEL \
98 a_name##_tls = a_initializer; \
99 a_attr pthread_key_t a_name##_tsd; \
100 a_attr bool a_name##_booted = false;
101 #elif (defined(_WIN32))
102 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
103 a_attr DWORD a_name##_tsd; \
104 a_attr bool a_name##_booted = false;
106 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
107 a_attr pthread_key_t a_name##_tsd; \
108 a_attr bool a_name##_booted = false;
111 /* malloc_tsd_funcs(). */
112 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
113 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
115 /* Initialization/cleanup. */ \
117 a_name##_tsd_cleanup_wrapper(void) \
120 if (a_name##_initialized) { \
121 a_name##_initialized = false; \
122 a_cleanup(&a_name##_tls); \
124 return (a_name##_initialized); \
127 a_name##_tsd_boot(void) \
130 if (a_cleanup != malloc_tsd_no_cleanup) { \
131 malloc_tsd_cleanup_register( \
132 &a_name##_tsd_cleanup_wrapper); \
134 a_name##_booted = true; \
139 a_name##_tsd_get(void) \
142 assert(a_name##_booted); \
143 return (&a_name##_tls); \
146 a_name##_tsd_set(a_type *val) \
149 assert(a_name##_booted); \
150 a_name##_tls = (*val); \
151 if (a_cleanup != malloc_tsd_no_cleanup) \
152 a_name##_initialized = true; \
154 #elif (defined(JEMALLOC_TLS))
155 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
157 /* Initialization/cleanup. */ \
159 a_name##_tsd_boot(void) \
162 if (a_cleanup != malloc_tsd_no_cleanup) { \
163 if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0) \
166 a_name##_booted = true; \
171 a_name##_tsd_get(void) \
174 assert(a_name##_booted); \
175 return (&a_name##_tls); \
178 a_name##_tsd_set(a_type *val) \
181 assert(a_name##_booted); \
182 a_name##_tls = (*val); \
183 if (a_cleanup != malloc_tsd_no_cleanup) { \
184 if (pthread_setspecific(a_name##_tsd, \
185 (void *)(&a_name##_tls))) { \
186 malloc_write("<jemalloc>: Error" \
187 " setting TSD for "#a_name"\n"); \
193 #elif (defined(_WIN32))
194 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
196 /* Data structure. */ \
200 } a_name##_tsd_wrapper_t; \
201 /* Initialization/cleanup. */ \
203 a_name##_tsd_cleanup_wrapper(void) \
205 a_name##_tsd_wrapper_t *wrapper; \
207 wrapper = (a_name##_tsd_wrapper_t *) TlsGetValue(a_name##_tsd); \
208 if (wrapper == NULL) \
210 if (a_cleanup != malloc_tsd_no_cleanup && \
211 wrapper->initialized) { \
212 a_type val = wrapper->val; \
213 a_type tsd_static_data = a_initializer; \
214 wrapper->initialized = false; \
215 wrapper->val = tsd_static_data; \
217 if (wrapper->initialized) { \
218 /* Trigger another cleanup round. */ \
222 malloc_tsd_dalloc(wrapper); \
226 a_name##_tsd_boot(void) \
229 a_name##_tsd = TlsAlloc(); \
230 if (a_name##_tsd == TLS_OUT_OF_INDEXES) \
232 if (a_cleanup != malloc_tsd_no_cleanup) { \
233 malloc_tsd_cleanup_register( \
234 &a_name##_tsd_cleanup_wrapper); \
236 a_name##_booted = true; \
240 a_attr a_name##_tsd_wrapper_t * \
241 a_name##_tsd_get_wrapper(void) \
243 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \
244 TlsGetValue(a_name##_tsd); \
246 if (wrapper == NULL) { \
247 wrapper = (a_name##_tsd_wrapper_t *) \
248 malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \
249 if (wrapper == NULL) { \
250 malloc_write("<jemalloc>: Error allocating" \
251 " TSD for "#a_name"\n"); \
254 static a_type tsd_static_data = a_initializer; \
255 wrapper->initialized = false; \
256 wrapper->val = tsd_static_data; \
258 if (!TlsSetValue(a_name##_tsd, (void *)wrapper)) { \
259 malloc_write("<jemalloc>: Error setting" \
260 " TSD for "#a_name"\n"); \
267 a_name##_tsd_get(void) \
269 a_name##_tsd_wrapper_t *wrapper; \
271 assert(a_name##_booted); \
272 wrapper = a_name##_tsd_get_wrapper(); \
273 return (&wrapper->val); \
276 a_name##_tsd_set(a_type *val) \
278 a_name##_tsd_wrapper_t *wrapper; \
280 assert(a_name##_booted); \
281 wrapper = a_name##_tsd_get_wrapper(); \
282 wrapper->val = *(val); \
283 if (a_cleanup != malloc_tsd_no_cleanup) \
284 wrapper->initialized = true; \
287 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
289 /* Data structure. */ \
293 } a_name##_tsd_wrapper_t; \
294 /* Initialization/cleanup. */ \
296 a_name##_tsd_cleanup_wrapper(void *arg) \
298 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\
300 if (a_cleanup != malloc_tsd_no_cleanup && \
301 wrapper->initialized) { \
302 wrapper->initialized = false; \
303 a_cleanup(&wrapper->val); \
304 if (wrapper->initialized) { \
305 /* Trigger another cleanup round. */ \
306 if (pthread_setspecific(a_name##_tsd, \
307 (void *)wrapper)) { \
308 malloc_write("<jemalloc>: Error" \
309 " setting TSD for "#a_name"\n"); \
316 malloc_tsd_dalloc(wrapper); \
319 a_name##_tsd_boot(void) \
322 if (pthread_key_create(&a_name##_tsd, \
323 a_name##_tsd_cleanup_wrapper) != 0) \
325 a_name##_booted = true; \
329 a_attr a_name##_tsd_wrapper_t * \
330 a_name##_tsd_get_wrapper(void) \
332 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \
333 pthread_getspecific(a_name##_tsd); \
335 if (wrapper == NULL) { \
336 wrapper = (a_name##_tsd_wrapper_t *) \
337 malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \
338 if (wrapper == NULL) { \
339 malloc_write("<jemalloc>: Error allocating" \
340 " TSD for "#a_name"\n"); \
343 static a_type tsd_static_data = a_initializer; \
344 wrapper->initialized = false; \
345 wrapper->val = tsd_static_data; \
347 if (pthread_setspecific(a_name##_tsd, \
348 (void *)wrapper)) { \
349 malloc_write("<jemalloc>: Error setting" \
350 " TSD for "#a_name"\n"); \
357 a_name##_tsd_get(void) \
359 a_name##_tsd_wrapper_t *wrapper; \
361 assert(a_name##_booted); \
362 wrapper = a_name##_tsd_get_wrapper(); \
363 return (&wrapper->val); \
366 a_name##_tsd_set(a_type *val) \
368 a_name##_tsd_wrapper_t *wrapper; \
370 assert(a_name##_booted); \
371 wrapper = a_name##_tsd_get_wrapper(); \
372 wrapper->val = *(val); \
373 if (a_cleanup != malloc_tsd_no_cleanup) \
374 wrapper->initialized = true; \
378 #endif /* JEMALLOC_H_TYPES */
379 /******************************************************************************/
380 #ifdef JEMALLOC_H_STRUCTS
382 #endif /* JEMALLOC_H_STRUCTS */
383 /******************************************************************************/
384 #ifdef JEMALLOC_H_EXTERNS
386 void *malloc_tsd_malloc(size_t size);
387 void malloc_tsd_dalloc(void *wrapper);
388 void malloc_tsd_no_cleanup(void *);
389 void malloc_tsd_cleanup_register(bool (*f)(void));
390 void malloc_tsd_boot(void);
392 #endif /* JEMALLOC_H_EXTERNS */
393 /******************************************************************************/
394 #ifdef JEMALLOC_H_INLINES
396 #endif /* JEMALLOC_H_INLINES */
397 /******************************************************************************/