]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/jemalloc/include/jemalloc/internal/tsd.h
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / jemalloc / include / jemalloc / internal / tsd.h
1 /******************************************************************************/
2 #ifdef JEMALLOC_H_TYPES
3
4 /* Maximum number of malloc_tsd users with cleanup functions. */
5 #define MALLOC_TSD_CLEANUPS_MAX 8
6
7 typedef bool (*malloc_tsd_cleanup_t)(void);
8
9 /*
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:
14  *
15  * In example.h:
16  *   typedef struct {
17  *           int x;
18  *           int y;
19  *   } example_t;
20  *   #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0})
21  *   malloc_tsd_protos(, example, example_t *)
22  *   malloc_tsd_externs(example, example_t *)
23  * In example.c:
24  *   malloc_tsd_data(, example, example_t *, EX_INITIALIZER)
25  *   malloc_tsd_funcs(, example, example_t *, EX_INITIALIZER,
26  *       example_tsd_cleanup)
27  *
28  * The result is a set of generated functions, e.g.:
29  *
30  *   bool example_tsd_boot(void) {...}
31  *   example_t **example_tsd_get() {...}
32  *   void example_tsd_set(example_t **val) {...}
33  *
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.:
39  *
40  *   void
41  *   example_tsd_cleanup(void *arg)
42  *   {
43  *           example_t *example = *(example_t **)arg;
44  *
45  *           [...]
46  *           if ([want the cleanup function to be called again]) {
47  *                   example_tsd_set(&example);
48  *           }
49  *   }
50  *
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
54  * non-NULL.
55  */
56
57 /* malloc_tsd_protos(). */
58 #define malloc_tsd_protos(a_attr, a_name, a_type)                       \
59 a_attr bool                                                             \
60 a_name##_tsd_boot(void);                                                \
61 a_attr a_type *                                                         \
62 a_name##_tsd_get(void);                                                 \
63 a_attr void                                                             \
64 a_name##_tsd_set(a_type *val);
65
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;
81 #else
82 #define malloc_tsd_externs(a_name, a_type)                              \
83 extern pthread_key_t    a_name##_tsd;                                   \
84 extern bool             a_name##_booted;
85 #endif
86
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;
105 #else
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;
109 #endif
110
111 /* malloc_tsd_funcs(). */
112 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
113 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,         \
114     a_cleanup)                                                          \
115 /* Initialization/cleanup. */                                           \
116 a_attr bool                                                             \
117 a_name##_tsd_cleanup_wrapper(void)                                      \
118 {                                                                       \
119                                                                         \
120         if (a_name##_initialized) {                                     \
121                 a_name##_initialized = false;                           \
122                 a_cleanup(&a_name##_tls);                               \
123         }                                                               \
124         return (a_name##_initialized);                                  \
125 }                                                                       \
126 a_attr bool                                                             \
127 a_name##_tsd_boot(void)                                                 \
128 {                                                                       \
129                                                                         \
130         if (a_cleanup != malloc_tsd_no_cleanup) {                       \
131                 malloc_tsd_cleanup_register(                            \
132                     &a_name##_tsd_cleanup_wrapper);                     \
133         }                                                               \
134         a_name##_booted = true;                                         \
135         return (false);                                                 \
136 }                                                                       \
137 /* Get/set. */                                                          \
138 a_attr a_type *                                                         \
139 a_name##_tsd_get(void)                                                  \
140 {                                                                       \
141                                                                         \
142         assert(a_name##_booted);                                        \
143         return (&a_name##_tls);                                         \
144 }                                                                       \
145 a_attr void                                                             \
146 a_name##_tsd_set(a_type *val)                                           \
147 {                                                                       \
148                                                                         \
149         assert(a_name##_booted);                                        \
150         a_name##_tls = (*val);                                          \
151         if (a_cleanup != malloc_tsd_no_cleanup)                         \
152                 a_name##_initialized = true;                            \
153 }
154 #elif (defined(JEMALLOC_TLS))
155 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,         \
156     a_cleanup)                                                          \
157 /* Initialization/cleanup. */                                           \
158 a_attr bool                                                             \
159 a_name##_tsd_boot(void)                                                 \
160 {                                                                       \
161                                                                         \
162         if (a_cleanup != malloc_tsd_no_cleanup) {                       \
163                 if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0)  \
164                         return (true);                                  \
165         }                                                               \
166         a_name##_booted = true;                                         \
167         return (false);                                                 \
168 }                                                                       \
169 /* Get/set. */                                                          \
170 a_attr a_type *                                                         \
171 a_name##_tsd_get(void)                                                  \
172 {                                                                       \
173                                                                         \
174         assert(a_name##_booted);                                        \
175         return (&a_name##_tls);                                         \
176 }                                                                       \
177 a_attr void                                                             \
178 a_name##_tsd_set(a_type *val)                                           \
179 {                                                                       \
180                                                                         \
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");            \
188                         if (opt_abort)                                  \
189                                 abort();                                \
190                 }                                                       \
191         }                                                               \
192 }
193 #elif (defined(_WIN32))
194 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,         \
195     a_cleanup)                                                          \
196 /* Data structure. */                                                   \
197 typedef struct {                                                        \
198         bool    initialized;                                            \
199         a_type  val;                                                    \
200 } a_name##_tsd_wrapper_t;                                               \
201 /* Initialization/cleanup. */                                           \
202 a_attr bool                                                             \
203 a_name##_tsd_cleanup_wrapper(void)                                      \
204 {                                                                       \
205         a_name##_tsd_wrapper_t *wrapper;                                \
206                                                                         \
207         wrapper = (a_name##_tsd_wrapper_t *) TlsGetValue(a_name##_tsd); \
208         if (wrapper == NULL)                                            \
209                 return (false);                                         \
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;                         \
216                 a_cleanup(&val);                                        \
217                 if (wrapper->initialized) {                             \
218                         /* Trigger another cleanup round. */            \
219                         return (true);                                  \
220                 }                                                       \
221         }                                                               \
222         malloc_tsd_dalloc(wrapper);                                     \
223         return (false);                                                 \
224 }                                                                       \
225 a_attr bool                                                             \
226 a_name##_tsd_boot(void)                                                 \
227 {                                                                       \
228                                                                         \
229         a_name##_tsd = TlsAlloc();                                      \
230         if (a_name##_tsd == TLS_OUT_OF_INDEXES)                         \
231                 return (true);                                          \
232         if (a_cleanup != malloc_tsd_no_cleanup) {                       \
233                 malloc_tsd_cleanup_register(                            \
234                     &a_name##_tsd_cleanup_wrapper);                     \
235         }                                                               \
236         a_name##_booted = true;                                         \
237         return (false);                                                 \
238 }                                                                       \
239 /* Get/set. */                                                          \
240 a_attr a_name##_tsd_wrapper_t *                                         \
241 a_name##_tsd_get_wrapper(void)                                          \
242 {                                                                       \
243         a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)    \
244             TlsGetValue(a_name##_tsd);                                  \
245                                                                         \
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");                    \
252                         abort();                                        \
253                 } else {                                                \
254                         static a_type tsd_static_data = a_initializer;  \
255                         wrapper->initialized = false;                   \
256                         wrapper->val = tsd_static_data;                 \
257                 }                                                       \
258                 if (!TlsSetValue(a_name##_tsd, (void *)wrapper)) {      \
259                         malloc_write("<jemalloc>: Error setting"        \
260                             " TSD for "#a_name"\n");                    \
261                         abort();                                        \
262                 }                                                       \
263         }                                                               \
264         return (wrapper);                                               \
265 }                                                                       \
266 a_attr a_type *                                                         \
267 a_name##_tsd_get(void)                                                  \
268 {                                                                       \
269         a_name##_tsd_wrapper_t *wrapper;                                \
270                                                                         \
271         assert(a_name##_booted);                                        \
272         wrapper = a_name##_tsd_get_wrapper();                           \
273         return (&wrapper->val);                                         \
274 }                                                                       \
275 a_attr void                                                             \
276 a_name##_tsd_set(a_type *val)                                           \
277 {                                                                       \
278         a_name##_tsd_wrapper_t *wrapper;                                \
279                                                                         \
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;                            \
285 }
286 #else
287 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,         \
288     a_cleanup)                                                          \
289 /* Data structure. */                                                   \
290 typedef struct {                                                        \
291         bool    initialized;                                            \
292         a_type  val;                                                    \
293 } a_name##_tsd_wrapper_t;                                               \
294 /* Initialization/cleanup. */                                           \
295 a_attr void                                                             \
296 a_name##_tsd_cleanup_wrapper(void *arg)                                 \
297 {                                                                       \
298         a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\
299                                                                         \
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");    \
310                                 if (opt_abort)                          \
311                                         abort();                        \
312                         }                                               \
313                         return;                                         \
314                 }                                                       \
315         }                                                               \
316         malloc_tsd_dalloc(wrapper);                                     \
317 }                                                                       \
318 a_attr bool                                                             \
319 a_name##_tsd_boot(void)                                                 \
320 {                                                                       \
321                                                                         \
322         if (pthread_key_create(&a_name##_tsd,                           \
323             a_name##_tsd_cleanup_wrapper) != 0)                         \
324                 return (true);                                          \
325         a_name##_booted = true;                                         \
326         return (false);                                                 \
327 }                                                                       \
328 /* Get/set. */                                                          \
329 a_attr a_name##_tsd_wrapper_t *                                         \
330 a_name##_tsd_get_wrapper(void)                                          \
331 {                                                                       \
332         a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)    \
333             pthread_getspecific(a_name##_tsd);                          \
334                                                                         \
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");                    \
341                         abort();                                        \
342                 } else {                                                \
343                         static a_type tsd_static_data = a_initializer;  \
344                         wrapper->initialized = false;                   \
345                         wrapper->val = tsd_static_data;                 \
346                 }                                                       \
347                 if (pthread_setspecific(a_name##_tsd,                   \
348                     (void *)wrapper)) {                                 \
349                         malloc_write("<jemalloc>: Error setting"        \
350                             " TSD for "#a_name"\n");                    \
351                         abort();                                        \
352                 }                                                       \
353         }                                                               \
354         return (wrapper);                                               \
355 }                                                                       \
356 a_attr a_type *                                                         \
357 a_name##_tsd_get(void)                                                  \
358 {                                                                       \
359         a_name##_tsd_wrapper_t *wrapper;                                \
360                                                                         \
361         assert(a_name##_booted);                                        \
362         wrapper = a_name##_tsd_get_wrapper();                           \
363         return (&wrapper->val);                                         \
364 }                                                                       \
365 a_attr void                                                             \
366 a_name##_tsd_set(a_type *val)                                           \
367 {                                                                       \
368         a_name##_tsd_wrapper_t *wrapper;                                \
369                                                                         \
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;                            \
375 }
376 #endif
377
378 #endif /* JEMALLOC_H_TYPES */
379 /******************************************************************************/
380 #ifdef JEMALLOC_H_STRUCTS
381
382 #endif /* JEMALLOC_H_STRUCTS */
383 /******************************************************************************/
384 #ifdef JEMALLOC_H_EXTERNS
385
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);
391
392 #endif /* JEMALLOC_H_EXTERNS */
393 /******************************************************************************/
394 #ifdef JEMALLOC_H_INLINES
395
396 #endif /* JEMALLOC_H_INLINES */
397 /******************************************************************************/