1*8e33eff8Schristos #ifdef JEMALLOC_INTERNAL_TSD_WIN_H 2*8e33eff8Schristos #error This file should be included only once, by tsd.h. 3*8e33eff8Schristos #endif 4*8e33eff8Schristos #define JEMALLOC_INTERNAL_TSD_WIN_H 5*8e33eff8Schristos 6*8e33eff8Schristos typedef struct { 7*8e33eff8Schristos bool initialized; 8*8e33eff8Schristos tsd_t val; 9*8e33eff8Schristos } tsd_wrapper_t; 10*8e33eff8Schristos 11*8e33eff8Schristos extern DWORD tsd_tsd; 12*8e33eff8Schristos extern tsd_wrapper_t tsd_boot_wrapper; 13*8e33eff8Schristos extern bool tsd_booted; 14*8e33eff8Schristos 15*8e33eff8Schristos /* Initialization/cleanup. */ 16*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE bool 17*8e33eff8Schristos tsd_cleanup_wrapper(void) { 18*8e33eff8Schristos DWORD error = GetLastError(); 19*8e33eff8Schristos tsd_wrapper_t *wrapper = (tsd_wrapper_t *)TlsGetValue(tsd_tsd); 20*8e33eff8Schristos SetLastError(error); 21*8e33eff8Schristos 22*8e33eff8Schristos if (wrapper == NULL) { 23*8e33eff8Schristos return false; 24*8e33eff8Schristos } 25*8e33eff8Schristos 26*8e33eff8Schristos if (wrapper->initialized) { 27*8e33eff8Schristos wrapper->initialized = false; 28*8e33eff8Schristos tsd_cleanup(&wrapper->val); 29*8e33eff8Schristos if (wrapper->initialized) { 30*8e33eff8Schristos /* Trigger another cleanup round. */ 31*8e33eff8Schristos return true; 32*8e33eff8Schristos } 33*8e33eff8Schristos } 34*8e33eff8Schristos malloc_tsd_dalloc(wrapper); 35*8e33eff8Schristos return false; 36*8e33eff8Schristos } 37*8e33eff8Schristos 38*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void 39*8e33eff8Schristos tsd_wrapper_set(tsd_wrapper_t *wrapper) { 40*8e33eff8Schristos if (!TlsSetValue(tsd_tsd, (void *)wrapper)) { 41*8e33eff8Schristos malloc_write("<jemalloc>: Error setting TSD\n"); 42*8e33eff8Schristos abort(); 43*8e33eff8Schristos } 44*8e33eff8Schristos } 45*8e33eff8Schristos 46*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE tsd_wrapper_t * 47*8e33eff8Schristos tsd_wrapper_get(bool init) { 48*8e33eff8Schristos DWORD error = GetLastError(); 49*8e33eff8Schristos tsd_wrapper_t *wrapper = (tsd_wrapper_t *) TlsGetValue(tsd_tsd); 50*8e33eff8Schristos SetLastError(error); 51*8e33eff8Schristos 52*8e33eff8Schristos if (init && unlikely(wrapper == NULL)) { 53*8e33eff8Schristos wrapper = (tsd_wrapper_t *) 54*8e33eff8Schristos malloc_tsd_malloc(sizeof(tsd_wrapper_t)); 55*8e33eff8Schristos if (wrapper == NULL) { 56*8e33eff8Schristos malloc_write("<jemalloc>: Error allocating TSD\n"); 57*8e33eff8Schristos abort(); 58*8e33eff8Schristos } else { 59*8e33eff8Schristos wrapper->initialized = false; 60*8e33eff8Schristos /* MSVC is finicky about aggregate initialization. */ 61*8e33eff8Schristos tsd_t tsd_initializer = TSD_INITIALIZER; 62*8e33eff8Schristos wrapper->val = tsd_initializer; 63*8e33eff8Schristos } 64*8e33eff8Schristos tsd_wrapper_set(wrapper); 65*8e33eff8Schristos } 66*8e33eff8Schristos return wrapper; 67*8e33eff8Schristos } 68*8e33eff8Schristos 69*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE bool 70*8e33eff8Schristos tsd_boot0(void) { 71*8e33eff8Schristos tsd_tsd = TlsAlloc(); 72*8e33eff8Schristos if (tsd_tsd == TLS_OUT_OF_INDEXES) { 73*8e33eff8Schristos return true; 74*8e33eff8Schristos } 75*8e33eff8Schristos malloc_tsd_cleanup_register(&tsd_cleanup_wrapper); 76*8e33eff8Schristos tsd_wrapper_set(&tsd_boot_wrapper); 77*8e33eff8Schristos tsd_booted = true; 78*8e33eff8Schristos return false; 79*8e33eff8Schristos } 80*8e33eff8Schristos 81*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void 82*8e33eff8Schristos tsd_boot1(void) { 83*8e33eff8Schristos tsd_wrapper_t *wrapper; 84*8e33eff8Schristos wrapper = (tsd_wrapper_t *) 85*8e33eff8Schristos malloc_tsd_malloc(sizeof(tsd_wrapper_t)); 86*8e33eff8Schristos if (wrapper == NULL) { 87*8e33eff8Schristos malloc_write("<jemalloc>: Error allocating TSD\n"); 88*8e33eff8Schristos abort(); 89*8e33eff8Schristos } 90*8e33eff8Schristos tsd_boot_wrapper.initialized = false; 91*8e33eff8Schristos tsd_cleanup(&tsd_boot_wrapper.val); 92*8e33eff8Schristos wrapper->initialized = false; 93*8e33eff8Schristos tsd_t initializer = TSD_INITIALIZER; 94*8e33eff8Schristos wrapper->val = initializer; 95*8e33eff8Schristos tsd_wrapper_set(wrapper); 96*8e33eff8Schristos } 97*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE bool 98*8e33eff8Schristos tsd_boot(void) { 99*8e33eff8Schristos if (tsd_boot0()) { 100*8e33eff8Schristos return true; 101*8e33eff8Schristos } 102*8e33eff8Schristos tsd_boot1(); 103*8e33eff8Schristos return false; 104*8e33eff8Schristos } 105*8e33eff8Schristos 106*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE bool 107*8e33eff8Schristos tsd_booted_get(void) { 108*8e33eff8Schristos return tsd_booted; 109*8e33eff8Schristos } 110*8e33eff8Schristos 111*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE bool 112*8e33eff8Schristos tsd_get_allocates(void) { 113*8e33eff8Schristos return true; 114*8e33eff8Schristos } 115*8e33eff8Schristos 116*8e33eff8Schristos /* Get/set. */ 117*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE tsd_t * 118*8e33eff8Schristos tsd_get(bool init) { 119*8e33eff8Schristos tsd_wrapper_t *wrapper; 120*8e33eff8Schristos 121*8e33eff8Schristos assert(tsd_booted); 122*8e33eff8Schristos wrapper = tsd_wrapper_get(init); 123*8e33eff8Schristos if (tsd_get_allocates() && !init && wrapper == NULL) { 124*8e33eff8Schristos return NULL; 125*8e33eff8Schristos } 126*8e33eff8Schristos return &wrapper->val; 127*8e33eff8Schristos } 128*8e33eff8Schristos 129*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE void 130*8e33eff8Schristos tsd_set(tsd_t *val) { 131*8e33eff8Schristos tsd_wrapper_t *wrapper; 132*8e33eff8Schristos 133*8e33eff8Schristos assert(tsd_booted); 134*8e33eff8Schristos wrapper = tsd_wrapper_get(true); 135*8e33eff8Schristos if (likely(&wrapper->val != val)) { 136*8e33eff8Schristos wrapper->val = *(val); 137*8e33eff8Schristos } 138*8e33eff8Schristos wrapper->initialized = true; 139*8e33eff8Schristos } 140