tsd.h revision a19e87fbad020e8dd3d26682032929e8e5ae71c1
11c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/******************************************************************************/ 21c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#ifdef JEMALLOC_H_TYPES 31c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák 41c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* Maximum number of malloc_tsd users with cleanup functions. */ 51c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define MALLOC_TSD_CLEANUPS_MAX 8 61c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák 71c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáktypedef bool (*malloc_tsd_cleanup_t)(void); 81c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák 91c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* 101c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * TLS/TSD-agnostic macro-based implementation of thread-specific data. There 111c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * are four macros that support (at least) three use cases: file-private, 121c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * library-private, and library-private inlined. Following is an example 131c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * library-private tsd variable: 141c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * 151c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * In example.h: 161c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * typedef struct { 171c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * int x; 181c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * int y; 191c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * } example_t; 201c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0}) 211c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * malloc_tsd_protos(, example, example_t *) 221c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * malloc_tsd_externs(example, example_t *) 231c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * In example.c: 241c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * malloc_tsd_data(, example, example_t *, EX_INITIALIZER) 251c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * malloc_tsd_funcs(, example, example_t *, EX_INITIALIZER, 261c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * example_tsd_cleanup) 271c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * 281c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * The result is a set of generated functions, e.g.: 291c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * 301c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * bool example_tsd_boot(void) {...} 311c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * example_t **example_tsd_get() {...} 321c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * void example_tsd_set(example_t **val) {...} 331c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * 341c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * Note that all of the functions deal in terms of (a_type *) rather than 351c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * (a_type) so that it is possible to support non-pointer types (unlike 361c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is 371c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * cast to (void *). This means that the cleanup function needs to cast *and* 381c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * dereference the function argument, e.g.: 391c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * 401c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * void 411c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * example_tsd_cleanup(void *arg) 421c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * { 431c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * example_t *example = *(example_t **)arg; 441c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * 451c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * [...] 461c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * if ([want the cleanup function to be called again]) { 471c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * example_tsd_set(&example); 481c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * } 491c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * } 501c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * 511c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * If example_tsd_set() is called within example_tsd_cleanup(), it will be 521c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * called again. This is similar to how pthreads TSD destruction works, except 531c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * that pthreads only calls the cleanup function again if the value was set to 541c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * non-NULL. 551c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák */ 561c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák 571c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* malloc_tsd_protos(). */ 581c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_protos(a_attr, a_name, a_type) \ 591c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool \ 601c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_boot(void); \ 611c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr a_type * \ 621c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_get(void); \ 631c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr void \ 641c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_set(a_type *val); 651c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák 661c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* malloc_tsd_externs(). */ 671c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 681c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_externs(a_name, a_type) \ 691c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern __thread a_type a_name##_tls; \ 701c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern __thread bool a_name##_initialized; \ 711c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern bool a_name##_booted; 721c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#elif (defined(JEMALLOC_TLS)) 731c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_externs(a_name, a_type) \ 741c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern __thread a_type a_name##_tls; \ 751c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern pthread_key_t a_name##_tsd; \ 761c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern bool a_name##_booted; 771c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#elif (defined(_WIN32)) 781c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_externs(a_name, a_type) \ 791c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern DWORD a_name##_tsd; \ 801c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern bool a_name##_booted; 811c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#else 821c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_externs(a_name, a_type) \ 831c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern pthread_key_t a_name##_tsd; \ 841c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern bool a_name##_booted; 851c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#endif 861c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák 871c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* malloc_tsd_data(). */ 881c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 891c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 901c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr __thread a_type JEMALLOC_TLS_MODEL \ 911c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák a_name##_tls = a_initializer; \ 921c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr __thread bool JEMALLOC_TLS_MODEL \ 931c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák a_name##_initialized = false; \ 941c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool a_name##_booted = false; 951c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#elif (defined(JEMALLOC_TLS)) 961c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 971c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr __thread a_type JEMALLOC_TLS_MODEL \ 981c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák a_name##_tls = a_initializer; \ 991c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr pthread_key_t a_name##_tsd; \ 1001c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool a_name##_booted = false; 1011c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#elif (defined(_WIN32)) 1021c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 1031c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr DWORD a_name##_tsd; \ 1041c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool a_name##_booted = false; 1051c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#else 1061c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 1071c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr pthread_key_t a_name##_tsd; \ 1081c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool a_name##_booted = false; 1091c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#endif 1101c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák 1111c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* malloc_tsd_funcs(). */ 1121c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 1131c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 1141c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák a_cleanup) \ 1151c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* Initialization/cleanup. */ \ 1161c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool \ 1171c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_cleanup_wrapper(void) \ 1181c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{ \ 1191c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák \ 1201c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák if (a_name##_initialized) { \ 1211c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák a_name##_initialized = false; \ 1221c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák a_cleanup(&a_name##_tls); \ 1231c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák } \ 1241c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák return (a_name##_initialized); \ 1251c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák} \ 1261c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool \ 1271c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_boot(void) \ 1281c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{ \ 1291c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák \ 1301c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák if (a_cleanup != malloc_tsd_no_cleanup) { \ 1311c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák malloc_tsd_cleanup_register( \ 1321c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák &a_name##_tsd_cleanup_wrapper); \ 1331c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák } \ 1341c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák a_name##_booted = true; \ 1351c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák return (false); \ 1361c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák} \ 1371c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* Get/set. */ \ 1381c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr a_type * \ 1391c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_get(void) \ 1401c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{ \ 1411c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák \ 1421c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák assert(a_name##_booted); \ 1431c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák return (&a_name##_tls); \ 1441c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák} \ 1451c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr void \ 1461c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_set(a_type *val) \ 1471c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{ \ 1481c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák \ 1491c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák assert(a_name##_booted); \ 1501c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák a_name##_tls = (*val); \ 151 if (a_cleanup != malloc_tsd_no_cleanup) \ 152 a_name##_initialized = true; \ 153} 154#elif (defined(JEMALLOC_TLS)) 155#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 156 a_cleanup) \ 157/* Initialization/cleanup. */ \ 158a_attr bool \ 159a_name##_tsd_boot(void) \ 160{ \ 161 \ 162 if (a_cleanup != malloc_tsd_no_cleanup) { \ 163 if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0) \ 164 return (true); \ 165 } \ 166 a_name##_booted = true; \ 167 return (false); \ 168} \ 169/* Get/set. */ \ 170a_attr a_type * \ 171a_name##_tsd_get(void) \ 172{ \ 173 \ 174 assert(a_name##_booted); \ 175 return (&a_name##_tls); \ 176} \ 177a_attr void \ 178a_name##_tsd_set(a_type *val) \ 179{ \ 180 \ 181 assert(a_name##_booted); \ 182 a_name##_tls = (*val); \ 183 if (a_cleanup != malloc_tsd_no_cleanup) { \ 184 if (pthread_setspecific(a_name##_tsd, \ 185 (void *)(&a_name##_tls))) { \ 186 malloc_write("<jemalloc>: Error" \ 187 " setting TSD for "#a_name"\n"); \ 188 if (opt_abort) \ 189 abort(); \ 190 } \ 191 } \ 192} 193#elif (defined(_WIN32)) 194#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 195 a_cleanup) \ 196/* Data structure. */ \ 197typedef struct { \ 198 bool initialized; \ 199 a_type val; \ 200} a_name##_tsd_wrapper_t; \ 201/* Initialization/cleanup. */ \ 202a_attr bool \ 203a_name##_tsd_cleanup_wrapper(void) \ 204{ \ 205 a_name##_tsd_wrapper_t *wrapper; \ 206 \ 207 wrapper = (a_name##_tsd_wrapper_t *) TlsGetValue(a_name##_tsd); \ 208 if (wrapper == NULL) \ 209 return (false); \ 210 if (a_cleanup != malloc_tsd_no_cleanup && \ 211 wrapper->initialized) { \ 212 a_type val = wrapper->val; \ 213 a_type tsd_static_data = a_initializer; \ 214 wrapper->initialized = false; \ 215 wrapper->val = tsd_static_data; \ 216 a_cleanup(&val); \ 217 if (wrapper->initialized) { \ 218 /* Trigger another cleanup round. */ \ 219 return (true); \ 220 } \ 221 } \ 222 malloc_tsd_dalloc(wrapper); \ 223 return (false); \ 224} \ 225a_attr bool \ 226a_name##_tsd_boot(void) \ 227{ \ 228 \ 229 a_name##_tsd = TlsAlloc(); \ 230 if (a_name##_tsd == TLS_OUT_OF_INDEXES) \ 231 return (true); \ 232 if (a_cleanup != malloc_tsd_no_cleanup) { \ 233 malloc_tsd_cleanup_register( \ 234 &a_name##_tsd_cleanup_wrapper); \ 235 } \ 236 a_name##_booted = true; \ 237 return (false); \ 238} \ 239/* Get/set. */ \ 240a_attr a_name##_tsd_wrapper_t * \ 241a_name##_tsd_get_wrapper(void) \ 242{ \ 243 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \ 244 TlsGetValue(a_name##_tsd); \ 245 \ 246 if (wrapper == NULL) { \ 247 wrapper = (a_name##_tsd_wrapper_t *) \ 248 malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \ 249 if (wrapper == NULL) { \ 250 malloc_write("<jemalloc>: Error allocating" \ 251 " TSD for "#a_name"\n"); \ 252 abort(); \ 253 } else { \ 254 static a_type tsd_static_data = a_initializer; \ 255 wrapper->initialized = false; \ 256 wrapper->val = tsd_static_data; \ 257 } \ 258 if (!TlsSetValue(a_name##_tsd, (void *)wrapper)) { \ 259 malloc_write("<jemalloc>: Error setting" \ 260 " TSD for "#a_name"\n"); \ 261 abort(); \ 262 } \ 263 } \ 264 return (wrapper); \ 265} \ 266a_attr a_type * \ 267a_name##_tsd_get(void) \ 268{ \ 269 a_name##_tsd_wrapper_t *wrapper; \ 270 \ 271 assert(a_name##_booted); \ 272 wrapper = a_name##_tsd_get_wrapper(); \ 273 return (&wrapper->val); \ 274} \ 275a_attr void \ 276a_name##_tsd_set(a_type *val) \ 277{ \ 278 a_name##_tsd_wrapper_t *wrapper; \ 279 \ 280 assert(a_name##_booted); \ 281 wrapper = a_name##_tsd_get_wrapper(); \ 282 wrapper->val = *(val); \ 283 if (a_cleanup != malloc_tsd_no_cleanup) \ 284 wrapper->initialized = true; \ 285} 286#else 287#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 288 a_cleanup) \ 289/* Data structure. */ \ 290typedef struct { \ 291 bool initialized; \ 292 a_type val; \ 293} a_name##_tsd_wrapper_t; \ 294/* Initialization/cleanup. */ \ 295a_attr void \ 296a_name##_tsd_cleanup_wrapper(void *arg) \ 297{ \ 298 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\ 299 \ 300 if (a_cleanup != malloc_tsd_no_cleanup && \ 301 wrapper->initialized) { \ 302 wrapper->initialized = false; \ 303 a_cleanup(&wrapper->val); \ 304 if (wrapper->initialized) { \ 305 /* Trigger another cleanup round. */ \ 306 if (pthread_setspecific(a_name##_tsd, \ 307 (void *)wrapper)) { \ 308 malloc_write("<jemalloc>: Error" \ 309 " setting TSD for "#a_name"\n"); \ 310 if (opt_abort) \ 311 abort(); \ 312 } \ 313 return; \ 314 } \ 315 } \ 316 malloc_tsd_dalloc(wrapper); \ 317} \ 318a_attr bool \ 319a_name##_tsd_boot(void) \ 320{ \ 321 \ 322 if (pthread_key_create(&a_name##_tsd, \ 323 a_name##_tsd_cleanup_wrapper) != 0) \ 324 return (true); \ 325 a_name##_booted = true; \ 326 return (false); \ 327} \ 328/* Get/set. */ \ 329a_attr a_name##_tsd_wrapper_t * \ 330a_name##_tsd_get_wrapper(void) \ 331{ \ 332 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \ 333 pthread_getspecific(a_name##_tsd); \ 334 \ 335 if (wrapper == NULL) { \ 336 wrapper = (a_name##_tsd_wrapper_t *) \ 337 malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \ 338 if (wrapper == NULL) { \ 339 malloc_write("<jemalloc>: Error allocating" \ 340 " TSD for "#a_name"\n"); \ 341 abort(); \ 342 } else { \ 343 static a_type tsd_static_data = a_initializer; \ 344 wrapper->initialized = false; \ 345 wrapper->val = tsd_static_data; \ 346 } \ 347 if (pthread_setspecific(a_name##_tsd, \ 348 (void *)wrapper)) { \ 349 malloc_write("<jemalloc>: Error setting" \ 350 " TSD for "#a_name"\n"); \ 351 abort(); \ 352 } \ 353 } \ 354 return (wrapper); \ 355} \ 356a_attr a_type * \ 357a_name##_tsd_get(void) \ 358{ \ 359 a_name##_tsd_wrapper_t *wrapper; \ 360 \ 361 assert(a_name##_booted); \ 362 wrapper = a_name##_tsd_get_wrapper(); \ 363 return (&wrapper->val); \ 364} \ 365a_attr void \ 366a_name##_tsd_set(a_type *val) \ 367{ \ 368 a_name##_tsd_wrapper_t *wrapper; \ 369 \ 370 assert(a_name##_booted); \ 371 wrapper = a_name##_tsd_get_wrapper(); \ 372 wrapper->val = *(val); \ 373 if (a_cleanup != malloc_tsd_no_cleanup) \ 374 wrapper->initialized = true; \ 375} 376#endif 377 378#endif /* JEMALLOC_H_TYPES */ 379/******************************************************************************/ 380#ifdef JEMALLOC_H_STRUCTS 381 382#endif /* JEMALLOC_H_STRUCTS */ 383/******************************************************************************/ 384#ifdef JEMALLOC_H_EXTERNS 385 386void *malloc_tsd_malloc(size_t size); 387void malloc_tsd_dalloc(void *wrapper); 388void malloc_tsd_no_cleanup(void *); 389void malloc_tsd_cleanup_register(bool (*f)(void)); 390void malloc_tsd_boot(void); 391 392#endif /* JEMALLOC_H_EXTERNS */ 393/******************************************************************************/ 394#ifdef JEMALLOC_H_INLINES 395 396#endif /* JEMALLOC_H_INLINES */ 397/******************************************************************************/ 398