1b7eaed25SJason Evans #ifdef JEMALLOC_INTERNAL_TSD_GENERIC_H 2b7eaed25SJason Evans #error This file should be included only once, by tsd.h. 3b7eaed25SJason Evans #endif 4b7eaed25SJason Evans #define JEMALLOC_INTERNAL_TSD_GENERIC_H 5b7eaed25SJason Evans 6b7eaed25SJason Evans typedef struct tsd_init_block_s tsd_init_block_t; 7b7eaed25SJason Evans struct tsd_init_block_s { 8b7eaed25SJason Evans ql_elm(tsd_init_block_t) link; 9b7eaed25SJason Evans pthread_t thread; 10b7eaed25SJason Evans void *data; 11b7eaed25SJason Evans }; 12b7eaed25SJason Evans 13b7eaed25SJason Evans /* Defined in tsd.c, to allow the mutex headers to have tsd dependencies. */ 14b7eaed25SJason Evans typedef struct tsd_init_head_s tsd_init_head_t; 15b7eaed25SJason Evans 16b7eaed25SJason Evans typedef struct { 17b7eaed25SJason Evans bool initialized; 18b7eaed25SJason Evans tsd_t val; 19b7eaed25SJason Evans } tsd_wrapper_t; 20b7eaed25SJason Evans 21b7eaed25SJason Evans void *tsd_init_check_recursion(tsd_init_head_t *head, 22b7eaed25SJason Evans tsd_init_block_t *block); 23b7eaed25SJason Evans void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); 24b7eaed25SJason Evans 25b7eaed25SJason Evans extern pthread_key_t tsd_tsd; 26b7eaed25SJason Evans extern tsd_init_head_t tsd_init_head; 27b7eaed25SJason Evans extern tsd_wrapper_t tsd_boot_wrapper; 28b7eaed25SJason Evans extern bool tsd_booted; 29b7eaed25SJason Evans 30b7eaed25SJason Evans /* Initialization/cleanup. */ 31b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE void tsd_cleanup_wrapper(void * arg)32b7eaed25SJason Evanstsd_cleanup_wrapper(void *arg) { 33b7eaed25SJason Evans tsd_wrapper_t *wrapper = (tsd_wrapper_t *)arg; 34b7eaed25SJason Evans 35b7eaed25SJason Evans if (wrapper->initialized) { 36b7eaed25SJason Evans wrapper->initialized = false; 37b7eaed25SJason Evans tsd_cleanup(&wrapper->val); 38b7eaed25SJason Evans if (wrapper->initialized) { 39b7eaed25SJason Evans /* Trigger another cleanup round. */ 40b7eaed25SJason Evans if (pthread_setspecific(tsd_tsd, (void *)wrapper) != 0) 41b7eaed25SJason Evans { 42b7eaed25SJason Evans malloc_write("<jemalloc>: Error setting TSD\n"); 43b7eaed25SJason Evans if (opt_abort) { 44b7eaed25SJason Evans abort(); 45b7eaed25SJason Evans } 46b7eaed25SJason Evans } 47b7eaed25SJason Evans return; 48b7eaed25SJason Evans } 49b7eaed25SJason Evans } 50b7eaed25SJason Evans malloc_tsd_dalloc(wrapper); 51b7eaed25SJason Evans } 52b7eaed25SJason Evans 53b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE void tsd_wrapper_set(tsd_wrapper_t * wrapper)54b7eaed25SJason Evanstsd_wrapper_set(tsd_wrapper_t *wrapper) { 55b7eaed25SJason Evans if (pthread_setspecific(tsd_tsd, (void *)wrapper) != 0) { 56b7eaed25SJason Evans malloc_write("<jemalloc>: Error setting TSD\n"); 57b7eaed25SJason Evans abort(); 58b7eaed25SJason Evans } 59b7eaed25SJason Evans } 60b7eaed25SJason Evans 61b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE tsd_wrapper_t * tsd_wrapper_get(bool init)62b7eaed25SJason Evanstsd_wrapper_get(bool init) { 63b7eaed25SJason Evans tsd_wrapper_t *wrapper = (tsd_wrapper_t *)pthread_getspecific(tsd_tsd); 64b7eaed25SJason Evans 65b7eaed25SJason Evans if (init && unlikely(wrapper == NULL)) { 66b7eaed25SJason Evans tsd_init_block_t block; 67b7eaed25SJason Evans wrapper = (tsd_wrapper_t *) 68b7eaed25SJason Evans tsd_init_check_recursion(&tsd_init_head, &block); 69b7eaed25SJason Evans if (wrapper) { 70b7eaed25SJason Evans return wrapper; 71b7eaed25SJason Evans } 72b7eaed25SJason Evans wrapper = (tsd_wrapper_t *) 73b7eaed25SJason Evans malloc_tsd_malloc(sizeof(tsd_wrapper_t)); 74b7eaed25SJason Evans block.data = (void *)wrapper; 75b7eaed25SJason Evans if (wrapper == NULL) { 76b7eaed25SJason Evans malloc_write("<jemalloc>: Error allocating TSD\n"); 77b7eaed25SJason Evans abort(); 78b7eaed25SJason Evans } else { 79b7eaed25SJason Evans wrapper->initialized = false; 80*c5ad8142SEric van Gyzen JEMALLOC_DIAGNOSTIC_PUSH 81*c5ad8142SEric van Gyzen JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS 82b7eaed25SJason Evans tsd_t initializer = TSD_INITIALIZER; 83*c5ad8142SEric van Gyzen JEMALLOC_DIAGNOSTIC_POP 84b7eaed25SJason Evans wrapper->val = initializer; 85b7eaed25SJason Evans } 86b7eaed25SJason Evans tsd_wrapper_set(wrapper); 87b7eaed25SJason Evans tsd_init_finish(&tsd_init_head, &block); 88b7eaed25SJason Evans } 89b7eaed25SJason Evans return wrapper; 90b7eaed25SJason Evans } 91b7eaed25SJason Evans 92b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool tsd_boot0(void)93b7eaed25SJason Evanstsd_boot0(void) { 94b7eaed25SJason Evans if (pthread_key_create(&tsd_tsd, tsd_cleanup_wrapper) != 0) { 95b7eaed25SJason Evans return true; 96b7eaed25SJason Evans } 97b7eaed25SJason Evans tsd_wrapper_set(&tsd_boot_wrapper); 98b7eaed25SJason Evans tsd_booted = true; 99b7eaed25SJason Evans return false; 100b7eaed25SJason Evans } 101b7eaed25SJason Evans 102b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE void tsd_boot1(void)103b7eaed25SJason Evanstsd_boot1(void) { 104b7eaed25SJason Evans tsd_wrapper_t *wrapper; 105b7eaed25SJason Evans wrapper = (tsd_wrapper_t *)malloc_tsd_malloc(sizeof(tsd_wrapper_t)); 106b7eaed25SJason Evans if (wrapper == NULL) { 107b7eaed25SJason Evans malloc_write("<jemalloc>: Error allocating TSD\n"); 108b7eaed25SJason Evans abort(); 109b7eaed25SJason Evans } 110b7eaed25SJason Evans tsd_boot_wrapper.initialized = false; 111b7eaed25SJason Evans tsd_cleanup(&tsd_boot_wrapper.val); 112b7eaed25SJason Evans wrapper->initialized = false; 113*c5ad8142SEric van Gyzen JEMALLOC_DIAGNOSTIC_PUSH 114*c5ad8142SEric van Gyzen JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS 115b7eaed25SJason Evans tsd_t initializer = TSD_INITIALIZER; 116*c5ad8142SEric van Gyzen JEMALLOC_DIAGNOSTIC_POP 117b7eaed25SJason Evans wrapper->val = initializer; 118b7eaed25SJason Evans tsd_wrapper_set(wrapper); 119b7eaed25SJason Evans } 120b7eaed25SJason Evans 121b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool tsd_boot(void)122b7eaed25SJason Evanstsd_boot(void) { 123b7eaed25SJason Evans if (tsd_boot0()) { 124b7eaed25SJason Evans return true; 125b7eaed25SJason Evans } 126b7eaed25SJason Evans tsd_boot1(); 127b7eaed25SJason Evans return false; 128b7eaed25SJason Evans } 129b7eaed25SJason Evans 130b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool tsd_booted_get(void)131b7eaed25SJason Evanstsd_booted_get(void) { 132b7eaed25SJason Evans return tsd_booted; 133b7eaed25SJason Evans } 134b7eaed25SJason Evans 135b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool tsd_get_allocates(void)136b7eaed25SJason Evanstsd_get_allocates(void) { 137b7eaed25SJason Evans return true; 138b7eaed25SJason Evans } 139b7eaed25SJason Evans 140b7eaed25SJason Evans /* Get/set. */ 141b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE tsd_t * tsd_get(bool init)142b7eaed25SJason Evanstsd_get(bool init) { 143b7eaed25SJason Evans tsd_wrapper_t *wrapper; 144b7eaed25SJason Evans 145b7eaed25SJason Evans assert(tsd_booted); 146b7eaed25SJason Evans wrapper = tsd_wrapper_get(init); 147b7eaed25SJason Evans if (tsd_get_allocates() && !init && wrapper == NULL) { 148b7eaed25SJason Evans return NULL; 149b7eaed25SJason Evans } 150b7eaed25SJason Evans return &wrapper->val; 151b7eaed25SJason Evans } 152b7eaed25SJason Evans 153b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE void tsd_set(tsd_t * val)154b7eaed25SJason Evanstsd_set(tsd_t *val) { 155b7eaed25SJason Evans tsd_wrapper_t *wrapper; 156b7eaed25SJason Evans 157b7eaed25SJason Evans assert(tsd_booted); 158b7eaed25SJason Evans wrapper = tsd_wrapper_get(true); 159b7eaed25SJason Evans if (likely(&wrapper->val != val)) { 160b7eaed25SJason Evans wrapper->val = *(val); 161b7eaed25SJason Evans } 162b7eaed25SJason Evans wrapper->initialized = true; 163b7eaed25SJason Evans } 164