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