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;
78 #define malloc_tsd_externs(a_name, a_type) \
79 extern pthread_key_t a_name##_tsd; \
80 extern bool a_name##_booted;
83 /* malloc_tsd_data(). */
84 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
85 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
86 a_attr __thread a_type JEMALLOC_TLS_MODEL \
87 a_name##_tls = a_initializer; \
88 a_attr __thread bool JEMALLOC_TLS_MODEL \
89 a_name##_initialized = false; \
90 a_attr bool a_name##_booted = false;
91 #elif (defined(JEMALLOC_TLS))
92 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
93 a_attr __thread a_type JEMALLOC_TLS_MODEL \
94 a_name##_tls = a_initializer; \
95 a_attr pthread_key_t a_name##_tsd; \
96 a_attr bool a_name##_booted = false;
98 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
99 a_attr pthread_key_t a_name##_tsd; \
100 a_attr bool a_name##_booted = false;
103 /* malloc_tsd_funcs(). */
104 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
105 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
107 /* Initialization/cleanup. */ \
109 a_name##_tsd_cleanup_wrapper(void) \
112 if (a_name##_initialized) { \
113 a_name##_initialized = false; \
114 a_cleanup(&a_name##_tls); \
116 return (a_name##_initialized); \
119 a_name##_tsd_boot(void) \
122 if (a_cleanup != malloc_tsd_no_cleanup) { \
123 malloc_tsd_cleanup_register( \
124 &a_name##_tsd_cleanup_wrapper); \
126 a_name##_booted = true; \
131 a_name##_tsd_get(void) \
134 assert(a_name##_booted); \
135 return (&a_name##_tls); \
138 a_name##_tsd_set(a_type *val) \
141 assert(a_name##_booted); \
142 a_name##_tls = (*val); \
143 if (a_cleanup != malloc_tsd_no_cleanup) \
144 a_name##_initialized = true; \
146 #elif (defined(JEMALLOC_TLS))
147 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
149 /* Initialization/cleanup. */ \
151 a_name##_tsd_boot(void) \
154 if (a_cleanup != malloc_tsd_no_cleanup) { \
155 if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0) \
158 a_name##_booted = true; \
163 a_name##_tsd_get(void) \
166 assert(a_name##_booted); \
167 return (&a_name##_tls); \
170 a_name##_tsd_set(a_type *val) \
173 assert(a_name##_booted); \
174 a_name##_tls = (*val); \
175 if (a_cleanup != malloc_tsd_no_cleanup) { \
176 if (pthread_setspecific(a_name##_tsd, \
177 (void *)(&a_name##_tls))) { \
178 malloc_write("<jemalloc>: Error" \
179 " setting TSD for "#a_name"\n"); \
186 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
188 /* Data structure. */ \
192 } a_name##_tsd_wrapper_t; \
193 /* Initialization/cleanup. */ \
195 a_name##_tsd_cleanup_wrapper(void *arg) \
197 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\
199 if (a_cleanup != malloc_tsd_no_cleanup && \
200 wrapper->initialized) { \
201 wrapper->initialized = false; \
202 a_cleanup(&wrapper->val); \
203 if (wrapper->initialized) { \
204 /* Trigger another cleanup round. */ \
205 if (pthread_setspecific(a_name##_tsd, \
206 (void *)wrapper)) { \
207 malloc_write("<jemalloc>: Error" \
208 " setting TSD for "#a_name"\n"); \
215 malloc_tsd_dalloc(wrapper); \
218 a_name##_tsd_boot(void) \
221 if (pthread_key_create(&a_name##_tsd, \
222 a_name##_tsd_cleanup_wrapper) != 0) \
224 a_name##_booted = true; \
228 a_attr a_name##_tsd_wrapper_t * \
229 a_name##_tsd_get_wrapper(void) \
231 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \
232 pthread_getspecific(a_name##_tsd); \
234 if (wrapper == NULL) { \
235 wrapper = (a_name##_tsd_wrapper_t *) \
236 malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \
237 if (wrapper == NULL) { \
238 malloc_write("<jemalloc>: Error allocating" \
239 " TSD for "#a_name"\n"); \
242 static a_type tsd_static_data = a_initializer; \
243 wrapper->initialized = false; \
244 wrapper->val = tsd_static_data; \
246 if (pthread_setspecific(a_name##_tsd, \
247 (void *)wrapper)) { \
248 malloc_write("<jemalloc>: Error setting" \
249 " TSD for "#a_name"\n"); \
256 a_name##_tsd_get(void) \
258 a_name##_tsd_wrapper_t *wrapper; \
260 assert(a_name##_booted); \
261 wrapper = a_name##_tsd_get_wrapper(); \
262 return (&wrapper->val); \
265 a_name##_tsd_set(a_type *val) \
267 a_name##_tsd_wrapper_t *wrapper; \
269 assert(a_name##_booted); \
270 wrapper = a_name##_tsd_get_wrapper(); \
271 wrapper->val = *(val); \
272 if (a_cleanup != malloc_tsd_no_cleanup) \
273 wrapper->initialized = true; \
277 #endif /* JEMALLOC_H_TYPES */
278 /******************************************************************************/
279 #ifdef JEMALLOC_H_STRUCTS
281 #endif /* JEMALLOC_H_STRUCTS */
282 /******************************************************************************/
283 #ifdef JEMALLOC_H_EXTERNS
285 void *malloc_tsd_malloc(size_t size);
286 void malloc_tsd_dalloc(void *wrapper);
287 void malloc_tsd_no_cleanup(void *);
288 void malloc_tsd_cleanup_register(bool (*f)(void));
289 void malloc_tsd_boot(void);
291 #endif /* JEMALLOC_H_EXTERNS */
292 /******************************************************************************/
293 #ifdef JEMALLOC_H_INLINES
295 #endif /* JEMALLOC_H_INLINES */
296 /******************************************************************************/