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