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