2 #ifdef JEMALLOC_H_TYPES
5 #define MALLOC_TSD_CLEANUPS_MAX 2
7 typedef bool (*malloc_tsd_cleanup_t)(void);
9 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
11 typedef struct tsd_init_block_s tsd_init_block_t;
12 typedef struct tsd_init_head_s tsd_init_head_t;
15 typedef struct tsd_s tsd_t;
16 typedef struct tsdn_s tsdn_t;
18 #define TSDN_NULL ((tsdn_t *)0)
21 tsd_state_uninitialized,
24 tsd_state_reincarnated
79 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
80 #define malloc_tsd_types(a_name, a_type)
81 #elif (defined(JEMALLOC_TLS))
82 #define malloc_tsd_types(a_name, a_type)
83 #elif (defined(_WIN32))
84 #define malloc_tsd_types(a_name, a_type) \
88 } a_name##tsd_wrapper_t;
90 #define malloc_tsd_types(a_name, a_type) \
94 } a_name##tsd_wrapper_t;
98 #define malloc_tsd_protos(a_attr, a_name, a_type) \
100 a_name##tsd_boot0(void); \
102 a_name##tsd_boot1(void); \
104 a_name##tsd_boot(void); \
106 a_name##tsd_booted_get(void); \
108 a_name##tsd_get(bool init); \
110 a_name##tsd_set(a_type *val);
113 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
114 #define malloc_tsd_externs(a_name, a_type) \
115 extern __thread a_type a_name##tsd_tls; \
116 extern __thread bool a_name##tsd_initialized; \
117 extern bool a_name##tsd_booted;
118 #elif (defined(JEMALLOC_TLS))
119 #define malloc_tsd_externs(a_name, a_type) \
120 extern __thread a_type a_name##tsd_tls; \
121 extern pthread_key_t a_name##tsd_tsd; \
122 extern bool a_name##tsd_booted;
123 #elif (defined(_WIN32))
124 #define malloc_tsd_externs(a_name, a_type) \
125 extern DWORD a_name##tsd_tsd; \
126 extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \
127 extern bool a_name##tsd_booted;
129 #define malloc_tsd_externs(a_name, a_type) \
130 extern pthread_key_t a_name##tsd_tsd; \
131 extern tsd_init_head_t a_name##tsd_init_head; \
132 extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \
133 extern bool a_name##tsd_booted;
137 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
138 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
139 a_attr __thread a_type JEMALLOC_TLS_MODEL \
140 a_name##tsd_tls = a_initializer; \
141 a_attr __thread bool JEMALLOC_TLS_MODEL \
142 a_name##tsd_initialized = false; \
143 a_attr bool a_name##tsd_booted = false;
144 #elif (defined(JEMALLOC_TLS))
145 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
146 a_attr __thread a_type JEMALLOC_TLS_MODEL \
147 a_name##tsd_tls = a_initializer; \
148 a_attr pthread_key_t a_name##tsd_tsd; \
149 a_attr bool a_name##tsd_booted = false;
150 #elif (defined(_WIN32))
151 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
152 a_attr DWORD a_name##tsd_tsd; \
153 a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \
157 a_attr bool a_name##tsd_booted = false;
159 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
160 a_attr pthread_key_t a_name##tsd_tsd; \
161 a_attr tsd_init_head_t a_name##tsd_init_head = { \
162 ql_head_initializer(blocks), \
163 MALLOC_MUTEX_INITIALIZER \
165 a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \
169 a_attr bool a_name##tsd_booted = false;
173 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
174 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
178 a_name##tsd_cleanup_wrapper(void) \
181 if (a_name##tsd_initialized) { \
182 a_name##tsd_initialized = false; \
183 a_cleanup(&a_name##tsd_tls); \
185 return (a_name##tsd_initialized); \
188 a_name##tsd_boot0(void) \
191 if (a_cleanup != malloc_tsd_no_cleanup) { \
192 malloc_tsd_cleanup_register( \
193 &a_name##tsd_cleanup_wrapper); \
195 a_name##tsd_booted = true; \
199 a_name##tsd_boot1(void) \
205 a_name##tsd_boot(void) \
208 return (a_name##tsd_boot0()); \
211 a_name##tsd_booted_get(void) \
214 return (a_name##tsd_booted); \
217 a_name##tsd_get_allocates(void) \
224 a_name##tsd_get(bool init) \
227 assert(a_name##tsd_booted); \
228 return (&a_name##tsd_tls); \
231 a_name##tsd_set(a_type *val) \
234 assert(a_name##tsd_booted); \
235 a_name##tsd_tls = (*val); \
236 if (a_cleanup != malloc_tsd_no_cleanup) \
237 a_name##tsd_initialized = true; \
239 #elif (defined(JEMALLOC_TLS))
240 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
244 a_name##tsd_boot0(void) \
247 if (a_cleanup != malloc_tsd_no_cleanup) { \
248 if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \
252 a_name##tsd_booted = true; \
256 a_name##tsd_boot1(void) \
262 a_name##tsd_boot(void) \
265 return (a_name##tsd_boot0()); \
268 a_name##tsd_booted_get(void) \
271 return (a_name##tsd_booted); \
274 a_name##tsd_get_allocates(void) \
281 a_name##tsd_get(bool init) \
284 assert(a_name##tsd_booted); \
285 return (&a_name##tsd_tls); \
288 a_name##tsd_set(a_type *val) \
291 assert(a_name##tsd_booted); \
292 a_name##tsd_tls = (*val); \
293 if (a_cleanup != malloc_tsd_no_cleanup) { \
294 if (pthread_setspecific(a_name##tsd_tsd, \
295 (void *)(&a_name##tsd_tls))) { \
296 malloc_write("<jemalloc>: Error" \
297 " setting TSD for "#a_name"\n"); \
303 #elif (defined(_WIN32))
304 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
308 a_name##tsd_cleanup_wrapper(void) \
310 DWORD error = GetLastError(); \
311 a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \
312 TlsGetValue(a_name##tsd_tsd); \
313 SetLastError(error); \
315 if (wrapper == NULL) \
317 if (a_cleanup != malloc_tsd_no_cleanup && \
318 wrapper->initialized) { \
319 wrapper->initialized = false; \
320 a_cleanup(&wrapper->val); \
321 if (wrapper->initialized) { \
326 malloc_tsd_dalloc(wrapper); \
330 a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \
333 if (!TlsSetValue(a_name##tsd_tsd, (void *)wrapper)) { \
334 malloc_write("<jemalloc>: Error setting" \
335 " TSD for "#a_name"\n"); \
339 a_attr a_name##tsd_wrapper_t * \
340 a_name##tsd_wrapper_get(bool init) \
342 DWORD error = GetLastError(); \
343 a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \
344 TlsGetValue(a_name##tsd_tsd); \
345 SetLastError(error); \
347 if (init && unlikely(wrapper == NULL)) { \
348 wrapper = (a_name##tsd_wrapper_t *) \
349 malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
350 if (wrapper == NULL) { \
351 malloc_write("<jemalloc>: Error allocating" \
352 " TSD for "#a_name"\n"); \
355 wrapper->initialized = false; \
356 wrapper->val = a_initializer; \
358 a_name##tsd_wrapper_set(wrapper); \
363 a_name##tsd_boot0(void) \
366 a_name##tsd_tsd = TlsAlloc(); \
367 if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) \
369 if (a_cleanup != malloc_tsd_no_cleanup) { \
370 malloc_tsd_cleanup_register( \
371 &a_name##tsd_cleanup_wrapper); \
373 a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \
374 a_name##tsd_booted = true; \
378 a_name##tsd_boot1(void) \
380 a_name##tsd_wrapper_t *wrapper; \
381 wrapper = (a_name##tsd_wrapper_t *) \
382 malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
383 if (wrapper == NULL) { \
384 malloc_write("<jemalloc>: Error allocating" \
385 " TSD for "#a_name"\n"); \
388 memcpy(wrapper, &a_name##tsd_boot_wrapper, \
389 sizeof(a_name##tsd_wrapper_t)); \
390 a_name##tsd_wrapper_set(wrapper); \
393 a_name##tsd_boot(void) \
396 if (a_name##tsd_boot0()) \
398 a_name##tsd_boot1(); \
402 a_name##tsd_booted_get(void) \
405 return (a_name##tsd_booted); \
408 a_name##tsd_get_allocates(void) \
415 a_name##tsd_get(bool init) \
417 a_name##tsd_wrapper_t *wrapper; \
419 assert(a_name##tsd_booted); \
420 wrapper = a_name##tsd_wrapper_get(init); \
421 if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \
423 return (&wrapper->val); \
426 a_name##tsd_set(a_type *val) \
428 a_name##tsd_wrapper_t *wrapper; \
430 assert(a_name##tsd_booted); \
431 wrapper = a_name##tsd_wrapper_get(true); \
432 wrapper->val = *(val); \
433 if (a_cleanup != malloc_tsd_no_cleanup) \
434 wrapper->initialized = true; \
437 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
441 a_name##tsd_cleanup_wrapper(void *arg) \
443 a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *)arg; \
445 if (a_cleanup != malloc_tsd_no_cleanup && \
446 wrapper->initialized) { \
447 wrapper->initialized = false; \
448 a_cleanup(&wrapper->val); \
449 if (wrapper->initialized) { \
451 if (pthread_setspecific(a_name##tsd_tsd, \
452 (void *)wrapper)) { \
453 malloc_write("<jemalloc>: Error" \
454 " setting TSD for "#a_name"\n"); \
461 malloc_tsd_dalloc(wrapper); \
464 a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \
467 if (pthread_setspecific(a_name##tsd_tsd, \
468 (void *)wrapper)) { \
469 malloc_write("<jemalloc>: Error setting" \
470 " TSD for "#a_name"\n"); \
474 a_attr a_name##tsd_wrapper_t * \
475 a_name##tsd_wrapper_get(bool init) \
477 a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \
478 pthread_getspecific(a_name##tsd_tsd); \
480 if (init && unlikely(wrapper == NULL)) { \
481 tsd_init_block_t block; \
482 wrapper = (a_name##tsd_wrapper_t *) \
483 tsd_init_check_recursion(&a_name##tsd_init_head, \
487 wrapper = (a_name##tsd_wrapper_t *) \
488 malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
489 block.data = (void *)wrapper; \
490 if (wrapper == NULL) { \
491 malloc_write("<jemalloc>: Error allocating" \
492 " TSD for "#a_name"\n"); \
495 wrapper->initialized = false; \
496 wrapper->val = a_initializer; \
498 a_name##tsd_wrapper_set(wrapper); \
499 tsd_init_finish(&a_name##tsd_init_head, &block); \
504 a_name##tsd_boot0(void) \
507 if (pthread_key_create(&a_name##tsd_tsd, \
508 a_name##tsd_cleanup_wrapper) != 0) \
510 a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \
511 a_name##tsd_booted = true; \
515 a_name##tsd_boot1(void) \
517 a_name##tsd_wrapper_t *wrapper; \
518 wrapper = (a_name##tsd_wrapper_t *) \
519 malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
520 if (wrapper == NULL) { \
521 malloc_write("<jemalloc>: Error allocating" \
522 " TSD for "#a_name"\n"); \
525 memcpy(wrapper, &a_name##tsd_boot_wrapper, \
526 sizeof(a_name##tsd_wrapper_t)); \
527 a_name##tsd_wrapper_set(wrapper); \
530 a_name##tsd_boot(void) \
533 if (a_name##tsd_boot0()) \
535 a_name##tsd_boot1(); \
539 a_name##tsd_booted_get(void) \
542 return (a_name##tsd_booted); \
545 a_name##tsd_get_allocates(void) \
552 a_name##tsd_get(bool init) \
554 a_name##tsd_wrapper_t *wrapper; \
556 assert(a_name##tsd_booted); \
557 wrapper = a_name##tsd_wrapper_get(init); \
558 if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \
560 return (&wrapper->val); \
563 a_name##tsd_set(a_type *val) \
565 a_name##tsd_wrapper_t *wrapper; \
572 wrapper->val = *(
val); \
574 wrapper->initialized =
true; \
580 #ifdef JEMALLOC_H_STRUCTS
582 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
584 struct tsd_init_block_s {
589 struct tsd_init_head_s {
597 O(tcache, tcache_t *) \
598 O(thread_allocated, uint64_t) \
599 O(thread_deallocated, uint64_t) \
600 O(prof_tdata, prof_tdata_t *) \
601 O(iarena, arena_t *) \
602 O(arena, arena_t *) \
603 O(arenas_tdata, arena_tdata_t *) \
604 O(narenas_tdata, unsigned) \
605 O(arenas_tdata_bypass, bool) \
606 O(tcache_enabled, tcache_enabled_t) \
607 O(quarantine, quarantine_t *) \
608 O(witnesses, witness_list_t) \
609 O(witness_fork, bool) \
611 #define TSD_INITIALIZER { \
612 tsd_state_uninitialized, \
622 tcache_enabled_default, \
624 ql_head_initializer(witnesses), \
645 static const tsd_t tsd_initializer = TSD_INITIALIZER;
647 malloc_tsd_types(, tsd_t)
651 #ifdef JEMALLOC_H_EXTERNS
659 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
662 tsd_init_block_t *block);
669 #ifdef JEMALLOC_H_INLINES
671 #ifndef JEMALLOC_ENABLE_INLINE
679 t *tsd_##n##p_get(tsd_t *tsd); \
680 t tsd_##n##_get(tsd_t *tsd); \
681 void tsd_##n##_set(tsd_t *tsd, t n);
689 #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_))
690 malloc_tsd_externs(, tsd_t)
703 if (
unlikely(tsd->state != tsd_state_nominal)) {
704 if (tsd->state == tsd_state_uninitialized) {
705 tsd->state = tsd_state_nominal;
708 }
else if (tsd->state == tsd_state_purgatory) {
709 tsd->state = tsd_state_reincarnated;
712 if (
unlikely(tsd->state != tsd_state_reincarnated))
731 return ((tsdn_t *)tsd);
738 return (tsd->state == tsd_state_nominal);
742 JEMALLOC_ALWAYS_INLINE t * \
743 tsd_##n##p_get(tsd_t *tsd) \
749 JEMALLOC_ALWAYS_INLINE t \
750 tsd_##n##_get(tsd_t *tsd) \
753 return (*tsd_##n##p_get(tsd)); \
756 JEMALLOC_ALWAYS_INLINE void \
757 tsd_##n##_set(tsd_t *tsd, t n) \
760 assert(tsd->state == tsd_state_nominal); \
780 return (tsdn ==
NULL);
static static fork const void static count static fd link
#define JEMALLOC_ALWAYS_INLINE
assert(limit<=UINT32_MAX/2)
#define malloc_tsd_no_cleanup
#define malloc_tsd_malloc
#define malloc_tsd_dalloc
#define tsd_init_check_recursion
#define malloc_tsd_cleanup_register
#define tsd_get_allocates
static void lock(volatile int *lk)