TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
tsd.h
Go to the documentation of this file.
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 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
10  !defined(_WIN32))
11 typedef struct tsd_init_block_s tsd_init_block_t;
12 typedef struct tsd_init_head_s tsd_init_head_t;
13 #endif
14 
15 /*
16  * TLS/TSD-agnostic macro-based implementation of thread-specific data. There
17  * are four macros that support (at least) three use cases: file-private,
18  * library-private, and library-private inlined. Following is an example
19  * library-private tsd variable:
20  *
21  * In example.h:
22  * typedef struct {
23  * int x;
24  * int y;
25  * } example_t;
26  * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0})
27  * malloc_tsd_protos(, example, example_t *)
28  * malloc_tsd_externs(example, example_t *)
29  * In example.c:
30  * malloc_tsd_data(, example, example_t *, EX_INITIALIZER)
31  * malloc_tsd_funcs(, example, example_t *, EX_INITIALIZER,
32  * example_tsd_cleanup)
33  *
34  * The result is a set of generated functions, e.g.:
35  *
36  * bool example_tsd_boot(void) {...}
37  * example_t **example_tsd_get() {...}
38  * void example_tsd_set(example_t **val) {...}
39  *
40  * Note that all of the functions deal in terms of (a_type *) rather than
41  * (a_type) so that it is possible to support non-pointer types (unlike
42  * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is
43  * cast to (void *). This means that the cleanup function needs to cast *and*
44  * dereference the function argument, e.g.:
45  *
46  * void
47  * example_tsd_cleanup(void *arg)
48  * {
49  * example_t *example = *(example_t **)arg;
50  *
51  * [...]
52  * if ([want the cleanup function to be called again]) {
53  * example_tsd_set(&example);
54  * }
55  * }
56  *
57  * If example_tsd_set() is called within example_tsd_cleanup(), it will be
58  * called again. This is similar to how pthreads TSD destruction works, except
59  * that pthreads only calls the cleanup function again if the value was set to
60  * non-NULL.
61  */
62 
63 /* malloc_tsd_protos(). */
64 #define malloc_tsd_protos(a_attr, a_name, a_type) \
65 a_attr bool \
66 a_name##_tsd_boot(void); \
67 a_attr a_type * \
68 a_name##_tsd_get(void); \
69 a_attr void \
70 a_name##_tsd_set(a_type *val);
71 
72 /* malloc_tsd_externs(). */
73 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
74 #define malloc_tsd_externs(a_name, a_type) \
75 extern __thread a_type a_name##_tls; \
76 extern __thread bool a_name##_initialized; \
77 extern bool a_name##_booted;
78 #elif (defined(JEMALLOC_TLS))
79 #define malloc_tsd_externs(a_name, a_type) \
80 extern __thread a_type a_name##_tls; \
81 extern pthread_key_t a_name##_tsd; \
82 extern bool a_name##_booted;
83 #elif (defined(_WIN32))
84 #define malloc_tsd_externs(a_name, a_type) \
85 extern DWORD a_name##_tsd; \
86 extern bool a_name##_booted;
87 #else
88 #define malloc_tsd_externs(a_name, a_type) \
89 extern pthread_key_t a_name##_tsd; \
90 extern tsd_init_head_t a_name##_tsd_init_head; \
91 extern bool a_name##_booted;
92 #endif
93 
94 /* malloc_tsd_data(). */
95 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
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 __thread bool JEMALLOC_TLS_MODEL \
100  a_name##_initialized = false; \
101 a_attr bool a_name##_booted = false;
102 #elif (defined(JEMALLOC_TLS))
103 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
104 a_attr __thread a_type JEMALLOC_TLS_MODEL \
105  a_name##_tls = a_initializer; \
106 a_attr pthread_key_t a_name##_tsd; \
107 a_attr bool a_name##_booted = false;
108 #elif (defined(_WIN32))
109 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
110 a_attr DWORD a_name##_tsd; \
111 a_attr bool a_name##_booted = false;
112 #else
113 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
114 a_attr pthread_key_t a_name##_tsd; \
115 a_attr tsd_init_head_t a_name##_tsd_init_head = { \
116  ql_head_initializer(blocks), \
117  MALLOC_MUTEX_INITIALIZER \
118 }; \
119 a_attr bool a_name##_booted = false;
120 #endif
121 
122 /* malloc_tsd_funcs(). */
123 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
124 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
125  a_cleanup) \
126 /* Initialization/cleanup. */ \
127 a_attr bool \
128 a_name##_tsd_cleanup_wrapper(void) \
129 { \
130  \
131  if (a_name##_initialized) { \
132  a_name##_initialized = false; \
133  a_cleanup(&a_name##_tls); \
134  } \
135  return (a_name##_initialized); \
136 } \
137 a_attr bool \
138 a_name##_tsd_boot(void) \
139 { \
140  \
141  if (a_cleanup != malloc_tsd_no_cleanup) { \
142  malloc_tsd_cleanup_register( \
143  &a_name##_tsd_cleanup_wrapper); \
144  } \
145  a_name##_booted = true; \
146  return (false); \
147 } \
148 /* Get/set. */ \
149 a_attr a_type * \
150 a_name##_tsd_get(void) \
151 { \
152  \
153  assert(a_name##_booted); \
154  return (&a_name##_tls); \
155 } \
156 a_attr void \
157 a_name##_tsd_set(a_type *val) \
158 { \
159  \
160  assert(a_name##_booted); \
161  a_name##_tls = (*val); \
162  if (a_cleanup != malloc_tsd_no_cleanup) \
163  a_name##_initialized = true; \
164 }
165 #elif (defined(JEMALLOC_TLS))
166 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
167  a_cleanup) \
168 /* Initialization/cleanup. */ \
169 a_attr bool \
170 a_name##_tsd_boot(void) \
171 { \
172  \
173  if (a_cleanup != malloc_tsd_no_cleanup) { \
174  if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0) \
175  return (true); \
176  } \
177  a_name##_booted = true; \
178  return (false); \
179 } \
180 /* Get/set. */ \
181 a_attr a_type * \
182 a_name##_tsd_get(void) \
183 { \
184  \
185  assert(a_name##_booted); \
186  return (&a_name##_tls); \
187 } \
188 a_attr void \
189 a_name##_tsd_set(a_type *val) \
190 { \
191  \
192  assert(a_name##_booted); \
193  a_name##_tls = (*val); \
194  if (a_cleanup != malloc_tsd_no_cleanup) { \
195  if (pthread_setspecific(a_name##_tsd, \
196  (void *)(&a_name##_tls))) { \
197  malloc_write("<jemalloc>: Error" \
198  " setting TSD for "#a_name"\n"); \
199  if (opt_abort) \
200  abort(); \
201  } \
202  } \
203 }
204 #elif (defined(_WIN32))
205 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
206  a_cleanup) \
207 /* Data structure. */ \
208 typedef struct { \
209  bool initialized; \
210  a_type val; \
211 } a_name##_tsd_wrapper_t; \
212 /* Initialization/cleanup. */ \
213 a_attr bool \
214 a_name##_tsd_cleanup_wrapper(void) \
215 { \
216  a_name##_tsd_wrapper_t *wrapper; \
217  \
218  wrapper = (a_name##_tsd_wrapper_t *) TlsGetValue(a_name##_tsd); \
219  if (wrapper == NULL) \
220  return (false); \
221  if (a_cleanup != malloc_tsd_no_cleanup && \
222  wrapper->initialized) { \
223  a_type val = wrapper->val; \
224  a_type tsd_static_data = a_initializer; \
225  wrapper->initialized = false; \
226  wrapper->val = tsd_static_data; \
227  a_cleanup(&val); \
228  if (wrapper->initialized) { \
229  /* Trigger another cleanup round. */ \
230  return (true); \
231  } \
232  } \
233  malloc_tsd_dalloc(wrapper); \
234  return (false); \
235 } \
236 a_attr bool \
237 a_name##_tsd_boot(void) \
238 { \
239  \
240  a_name##_tsd = TlsAlloc(); \
241  if (a_name##_tsd == TLS_OUT_OF_INDEXES) \
242  return (true); \
243  if (a_cleanup != malloc_tsd_no_cleanup) { \
244  malloc_tsd_cleanup_register( \
245  &a_name##_tsd_cleanup_wrapper); \
246  } \
247  a_name##_booted = true; \
248  return (false); \
249 } \
250 /* Get/set. */ \
251 a_attr a_name##_tsd_wrapper_t * \
252 a_name##_tsd_get_wrapper(void) \
253 { \
254  a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \
255  TlsGetValue(a_name##_tsd); \
256  \
257  if (wrapper == NULL) { \
258  wrapper = (a_name##_tsd_wrapper_t *) \
259  malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \
260  if (wrapper == NULL) { \
261  malloc_write("<jemalloc>: Error allocating" \
262  " TSD for "#a_name"\n"); \
263  abort(); \
264  } else { \
265  static a_type tsd_static_data = a_initializer; \
266  wrapper->initialized = false; \
267  wrapper->val = tsd_static_data; \
268  } \
269  if (!TlsSetValue(a_name##_tsd, (void *)wrapper)) { \
270  malloc_write("<jemalloc>: Error setting" \
271  " TSD for "#a_name"\n"); \
272  abort(); \
273  } \
274  } \
275  return (wrapper); \
276 } \
277 a_attr a_type * \
278 a_name##_tsd_get(void) \
279 { \
280  a_name##_tsd_wrapper_t *wrapper; \
281  \
282  assert(a_name##_booted); \
283  wrapper = a_name##_tsd_get_wrapper(); \
284  return (&wrapper->val); \
285 } \
286 a_attr void \
287 a_name##_tsd_set(a_type *val) \
288 { \
289  a_name##_tsd_wrapper_t *wrapper; \
290  \
291  assert(a_name##_booted); \
292  wrapper = a_name##_tsd_get_wrapper(); \
293  wrapper->val = *(val); \
294  if (a_cleanup != malloc_tsd_no_cleanup) \
295  wrapper->initialized = true; \
296 }
297 #else
298 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
299  a_cleanup) \
300 /* Data structure. */ \
301 typedef struct { \
302  bool initialized; \
303  a_type val; \
304 } a_name##_tsd_wrapper_t; \
305 /* Initialization/cleanup. */ \
306 a_attr void \
307 a_name##_tsd_cleanup_wrapper(void *arg) \
308 { \
309  a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\
310  \
311  if (a_cleanup != malloc_tsd_no_cleanup && \
312  wrapper->initialized) { \
313  wrapper->initialized = false; \
314  a_cleanup(&wrapper->val); \
315  if (wrapper->initialized) { \
316  /* Trigger another cleanup round. */ \
317  if (pthread_setspecific(a_name##_tsd, \
318  (void *)wrapper)) { \
319  malloc_write("<jemalloc>: Error" \
320  " setting TSD for "#a_name"\n"); \
321  if (opt_abort) \
322  abort(); \
323  } \
324  return; \
325  } \
326  } \
327  malloc_tsd_dalloc(wrapper); \
328 } \
329 a_attr bool \
330 a_name##_tsd_boot(void) \
331 { \
332  \
333  if (pthread_key_create(&a_name##_tsd, \
334  a_name##_tsd_cleanup_wrapper) != 0) \
335  return (true); \
336  a_name##_booted = true; \
337  return (false); \
338 } \
339 /* Get/set. */ \
340 a_attr a_name##_tsd_wrapper_t * \
341 a_name##_tsd_get_wrapper(void) \
342 { \
343  a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \
344  pthread_getspecific(a_name##_tsd); \
345  \
346  if (wrapper == NULL) { \
347  tsd_init_block_t block; \
348  wrapper = tsd_init_check_recursion( \
349  &a_name##_tsd_init_head, &block); \
350  if (wrapper) \
351  return (wrapper); \
352  wrapper = (a_name##_tsd_wrapper_t *) \
353  malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \
354  block.data = wrapper; \
355  if (wrapper == NULL) { \
356  malloc_write("<jemalloc>: Error allocating" \
357  " TSD for "#a_name"\n"); \
358  abort(); \
359  } else { \
360  static a_type tsd_static_data = a_initializer; \
361  wrapper->initialized = false; \
362  wrapper->val = tsd_static_data; \
363  } \
364  if (pthread_setspecific(a_name##_tsd, \
365  (void *)wrapper)) { \
366  malloc_write("<jemalloc>: Error setting" \
367  " TSD for "#a_name"\n"); \
368  abort(); \
369  } \
370  tsd_init_finish(&a_name##_tsd_init_head, &block); \
371  } \
372  return (wrapper); \
373 } \
374 a_attr a_type * \
375 a_name##_tsd_get(void) \
376 { \
377  a_name##_tsd_wrapper_t *wrapper; \
378  \
379  assert(a_name##_booted); \
380  wrapper = a_name##_tsd_get_wrapper(); \
381  return (&wrapper->val); \
382 } \
383 a_attr void \
384 a_name##_tsd_set(a_type *val) \
385 { \
386  a_name##_tsd_wrapper_t *wrapper; \
387  \
388  assert(a_name##_booted); \
389  wrapper = a_name##_tsd_get_wrapper(); \
390  wrapper->val = *(val); \
391  if (a_cleanup != malloc_tsd_no_cleanup) \
392  wrapper->initialized = true; \
393 }
394 #endif
395 
396 #endif /* JEMALLOC_H_TYPES */
397 /******************************************************************************/
398 #ifdef JEMALLOC_H_STRUCTS
399 
400 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
401  !defined(_WIN32))
402 struct tsd_init_block_s {
403  ql_elm(tsd_init_block_t) link;
404  pthread_t thread;
405  void *data;
406 };
407 struct tsd_init_head_s {
408  ql_head(tsd_init_block_t) blocks;
409  malloc_mutex_t lock;
410 };
411 #endif
412 
413 #endif /* JEMALLOC_H_STRUCTS */
414 /******************************************************************************/
415 #ifdef JEMALLOC_H_EXTERNS
416 
417 void *malloc_tsd_malloc(size_t size);
418 void malloc_tsd_dalloc(void *wrapper);
419 void malloc_tsd_no_cleanup(void *);
420 void malloc_tsd_cleanup_register(bool (*f)(void));
421 void malloc_tsd_boot(void);
422 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
423  !defined(_WIN32))
424 void *tsd_init_check_recursion(tsd_init_head_t *head,
425  tsd_init_block_t *block);
426 void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block);
427 #endif
428 
429 #endif /* JEMALLOC_H_EXTERNS */
430 /******************************************************************************/
431 #ifdef JEMALLOC_H_INLINES
432 
433 #endif /* JEMALLOC_H_INLINES */
434 /******************************************************************************/
#define malloc_tsd_no_cleanup
Definition: private_namespace.h:249
#define malloc_tsd_cleanup_register
Definition: private_namespace.h:246
#define ql_head(a_type)
Definition: ql.h:4
#define malloc_tsd_dalloc
Definition: private_namespace.h:247
#define ql_elm(a_type)
Definition: ql.h:11
#define bool
Definition: CascPort.h:16
#define malloc_tsd_malloc
Definition: private_namespace.h:248
#define tsd_init_check_recursion
Definition: private_namespace.h:411
#define malloc_tsd_boot
Definition: private_namespace.h:245
#define tsd_init_finish
Definition: private_namespace.h:412