tsd.h revision 296221
1313535Sngie/******************************************************************************/ 2272343Sngie#ifdef JEMALLOC_H_TYPES 3272343Sngie 4272343Sngie/* Maximum number of malloc_tsd users with cleanup functions. */ 5272343Sngie#define MALLOC_TSD_CLEANUPS_MAX 2 6272343Sngie 7272343Sngietypedef bool (*malloc_tsd_cleanup_t)(void); 8272343Sngie 9272343Sngie#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ 10272343Sngie !defined(_WIN32)) 11272343Sngietypedef struct tsd_init_block_s tsd_init_block_t; 12272343Sngietypedef struct tsd_init_head_s tsd_init_head_t; 13272343Sngie#endif 14272343Sngie 15272343Sngietypedef struct tsd_s tsd_t; 16272343Sngie 17272343Sngietypedef enum { 18272343Sngie tsd_state_uninitialized, 19272343Sngie tsd_state_nominal, 20272343Sngie tsd_state_purgatory, 21272343Sngie tsd_state_reincarnated 22272343Sngie} tsd_state_t; 23272343Sngie 24272343Sngie/* 25272343Sngie * TLS/TSD-agnostic macro-based implementation of thread-specific data. There 26272343Sngie * are five macros that support (at least) three use cases: file-private, 27272343Sngie * library-private, and library-private inlined. Following is an example 28272343Sngie * library-private tsd variable: 29313535Sngie * 30313535Sngie * In example.h: 31313535Sngie * typedef struct { 32313535Sngie * int x; 33313535Sngie * int y; 34272343Sngie * } example_t; 35272343Sngie * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0}) 36313535Sngie * malloc_tsd_types(example_, example_t) 37272343Sngie * malloc_tsd_protos(, example_, example_t) 38272343Sngie * malloc_tsd_externs(example_, example_t) 39272343Sngie * In example.c: 40272343Sngie * malloc_tsd_data(, example_, example_t, EX_INITIALIZER) 41272343Sngie * malloc_tsd_funcs(, example_, example_t, EX_INITIALIZER, 42272343Sngie * example_tsd_cleanup) 43272343Sngie * 44272343Sngie * The result is a set of generated functions, e.g.: 45272343Sngie * 46272343Sngie * bool example_tsd_boot(void) {...} 47272343Sngie * example_t *example_tsd_get() {...} 48272343Sngie * void example_tsd_set(example_t *val) {...} 49272343Sngie * 50272343Sngie * Note that all of the functions deal in terms of (a_type *) rather than 51272343Sngie * (a_type) so that it is possible to support non-pointer types (unlike 52272343Sngie * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is 53272343Sngie * cast to (void *). This means that the cleanup function needs to cast the 54272343Sngie * function argument to (a_type *), then dereference the resulting pointer to 55272343Sngie * access fields, e.g. 56272343Sngie * 57272343Sngie * void 58272343Sngie * example_tsd_cleanup(void *arg) 59272343Sngie * { 60272343Sngie * example_t *example = (example_t *)arg; 61272343Sngie * 62272343Sngie * example->x = 42; 63272343Sngie * [...] 64272343Sngie * if ([want the cleanup function to be called again]) 65272343Sngie * example_tsd_set(example); 66272343Sngie * } 67272343Sngie * 68272343Sngie * If example_tsd_set() is called within example_tsd_cleanup(), it will be 69272343Sngie * called again. This is similar to how pthreads TSD destruction works, except 70272343Sngie * that pthreads only calls the cleanup function again if the value was set to 71272343Sngie * non-NULL. 72272343Sngie */ 73272343Sngie 74272343Sngie/* malloc_tsd_types(). */ 75272343Sngie#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 76272343Sngie#define malloc_tsd_types(a_name, a_type) 77272343Sngie#elif (defined(JEMALLOC_TLS)) 78272343Sngie#define malloc_tsd_types(a_name, a_type) 79272343Sngie#elif (defined(_WIN32)) 80272343Sngie#define malloc_tsd_types(a_name, a_type) \ 81272343Sngietypedef struct { \ 82272343Sngie bool initialized; \ 83276478Sngie a_type val; \ 84272343Sngie} a_name##tsd_wrapper_t; 85276478Sngie#else 86272343Sngie#define malloc_tsd_types(a_name, a_type) \ 87272343Sngietypedef struct { \ 88272343Sngie bool initialized; \ 89272343Sngie a_type val; \ 90272343Sngie} a_name##tsd_wrapper_t; 91272343Sngie#endif 92272343Sngie 93272343Sngie/* malloc_tsd_protos(). */ 94272343Sngie#define malloc_tsd_protos(a_attr, a_name, a_type) \ 95272343Sngiea_attr bool \ 96272343Sngiea_name##tsd_boot0(void); \ 97272343Sngiea_attr void \ 98272343Sngiea_name##tsd_boot1(void); \ 99272343Sngiea_attr bool \ 100272343Sngiea_name##tsd_boot(void); \ 101272343Sngiea_attr a_type * \ 102272343Sngiea_name##tsd_get(void); \ 103272343Sngiea_attr void \ 104272343Sngiea_name##tsd_set(a_type *val); 105272343Sngie 106272343Sngie/* malloc_tsd_externs(). */ 107272343Sngie#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 108272343Sngie#define malloc_tsd_externs(a_name, a_type) \ 109272343Sngieextern __thread a_type a_name##tsd_tls; \ 110272343Sngieextern __thread bool a_name##tsd_initialized; \ 111272343Sngieextern bool a_name##tsd_booted; 112272343Sngie#elif (defined(JEMALLOC_TLS)) 113272343Sngie#define malloc_tsd_externs(a_name, a_type) \ 114272343Sngieextern __thread a_type a_name##tsd_tls; \ 115272343Sngieextern pthread_key_t a_name##tsd_tsd; \ 116272343Sngieextern bool a_name##tsd_booted; 117272343Sngie#elif (defined(_WIN32)) 118272343Sngie#define malloc_tsd_externs(a_name, a_type) \ 119272343Sngieextern DWORD a_name##tsd_tsd; \ 120272343Sngieextern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ 121272343Sngieextern bool a_name##tsd_booted; 122272343Sngie#else 123276478Sngie#define malloc_tsd_externs(a_name, a_type) \ 124272343Sngieextern pthread_key_t a_name##tsd_tsd; \ 125272343Sngieextern tsd_init_head_t a_name##tsd_init_head; \ 126272343Sngieextern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ 127272343Sngieextern bool a_name##tsd_booted; 128272343Sngie#endif 129272343Sngie 130272343Sngie/* malloc_tsd_data(). */ 131272343Sngie#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 132272343Sngie#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 133272343Sngiea_attr __thread a_type JEMALLOC_TLS_MODEL \ 134272343Sngie a_name##tsd_tls = a_initializer; \ 135272343Sngiea_attr __thread bool JEMALLOC_TLS_MODEL \ 136272343Sngie a_name##tsd_initialized = false; \ 137276478Sngiea_attr bool a_name##tsd_booted = false; 138272343Sngie#elif (defined(JEMALLOC_TLS)) 139272343Sngie#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 140272343Sngiea_attr __thread a_type JEMALLOC_TLS_MODEL \ 141272343Sngie a_name##tsd_tls = a_initializer; \ 142272343Sngiea_attr pthread_key_t a_name##tsd_tsd; \ 143272343Sngiea_attr bool a_name##tsd_booted = false; 144272343Sngie#elif (defined(_WIN32)) 145272343Sngie#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 146272343Sngiea_attr DWORD a_name##tsd_tsd; \ 147272343Sngiea_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ 148272343Sngie false, \ 149272343Sngie a_initializer \ 150272343Sngie}; \ 151272343Sngiea_attr bool a_name##tsd_booted = false; 152272343Sngie#else 153272343Sngie#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 154272343Sngiea_attr pthread_key_t a_name##tsd_tsd; \ 155272343Sngiea_attr tsd_init_head_t a_name##tsd_init_head = { \ 156272343Sngie ql_head_initializer(blocks), \ 157272343Sngie MALLOC_MUTEX_INITIALIZER \ 158272343Sngie}; \ 159272343Sngiea_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ 160272343Sngie false, \ 161272343Sngie a_initializer \ 162272343Sngie}; \ 163272343Sngiea_attr bool a_name##tsd_booted = false; 164272343Sngie#endif 165272343Sngie 166272343Sngie/* malloc_tsd_funcs(). */ 167272343Sngie#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 168272343Sngie#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 169272343Sngie a_cleanup) \ 170272343Sngie/* Initialization/cleanup. */ \ 171272343Sngiea_attr bool \ 172272343Sngiea_name##tsd_cleanup_wrapper(void) \ 173272343Sngie{ \ 174272343Sngie \ 175272343Sngie if (a_name##tsd_initialized) { \ 176272343Sngie a_name##tsd_initialized = false; \ 177272343Sngie a_cleanup(&a_name##tsd_tls); \ 178272343Sngie } \ 179272343Sngie return (a_name##tsd_initialized); \ 180313498Sngie} \ 181313498Sngiea_attr bool \ 182272343Sngiea_name##tsd_boot0(void) \ 183272343Sngie{ \ 184272343Sngie \ 185272343Sngie if (a_cleanup != malloc_tsd_no_cleanup) { \ 186272343Sngie malloc_tsd_cleanup_register( \ 187272343Sngie &a_name##tsd_cleanup_wrapper); \ 188272343Sngie } \ 189272343Sngie a_name##tsd_booted = true; \ 190272343Sngie return (false); \ 191272343Sngie} \ 192272343Sngiea_attr void \ 193272343Sngiea_name##tsd_boot1(void) \ 194272343Sngie{ \ 195272343Sngie \ 196272343Sngie /* Do nothing. */ \ 197272343Sngie} \ 198272343Sngiea_attr bool \ 199272343Sngiea_name##tsd_boot(void) \ 200272343Sngie{ \ 201272343Sngie \ 202272343Sngie return (a_name##tsd_boot0()); \ 203272343Sngie} \ 204272343Sngie/* Get/set. */ \ 205272343Sngiea_attr a_type * \ 206272343Sngiea_name##tsd_get(void) \ 207272343Sngie{ \ 208272343Sngie \ 209272343Sngie assert(a_name##tsd_booted); \ 210272343Sngie return (&a_name##tsd_tls); \ 211272343Sngie} \ 212272343Sngiea_attr void \ 213272343Sngiea_name##tsd_set(a_type *val) \ 214272343Sngie{ \ 215272343Sngie \ 216272343Sngie assert(a_name##tsd_booted); \ 217272343Sngie a_name##tsd_tls = (*val); \ 218272343Sngie if (a_cleanup != malloc_tsd_no_cleanup) \ 219272343Sngie a_name##tsd_initialized = true; \ 220276478Sngie} 221272343Sngie#elif (defined(JEMALLOC_TLS)) 222272343Sngie#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 223272343Sngie a_cleanup) \ 224272343Sngie/* Initialization/cleanup. */ \ 225272343Sngiea_attr bool \ 226272343Sngiea_name##tsd_boot0(void) \ 227272343Sngie{ \ 228272343Sngie \ 229272343Sngie if (a_cleanup != malloc_tsd_no_cleanup) { \ 230272343Sngie if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \ 231272343Sngie 0) \ 232272343Sngie return (true); \ 233272343Sngie } \ 234276478Sngie a_name##tsd_booted = true; \ 235272343Sngie return (false); \ 236272343Sngie} \ 237272343Sngiea_attr void \ 238272343Sngiea_name##tsd_boot1(void) \ 239272343Sngie{ \ 240272343Sngie \ 241272343Sngie /* Do nothing. */ \ 242272343Sngie} \ 243272343Sngiea_attr bool \ 244272343Sngiea_name##tsd_boot(void) \ 245272343Sngie{ \ 246272343Sngie \ 247272343Sngie return (a_name##tsd_boot0()); \ 248272343Sngie} \ 249272343Sngie/* Get/set. */ \ 250272343Sngiea_attr a_type * \ 251272343Sngiea_name##tsd_get(void) \ 252272343Sngie{ \ 253272343Sngie \ 254272343Sngie assert(a_name##tsd_booted); \ 255272343Sngie return (&a_name##tsd_tls); \ 256272343Sngie} \ 257272343Sngiea_attr void \ 258272343Sngiea_name##tsd_set(a_type *val) \ 259272343Sngie{ \ 260272343Sngie \ 261272343Sngie assert(a_name##tsd_booted); \ 262272343Sngie a_name##tsd_tls = (*val); \ 263272343Sngie if (a_cleanup != malloc_tsd_no_cleanup) { \ 264272343Sngie if (pthread_setspecific(a_name##tsd_tsd, \ 265272343Sngie (void *)(&a_name##tsd_tls))) { \ 266272343Sngie malloc_write("<jemalloc>: Error" \ 267272343Sngie " setting TSD for "#a_name"\n"); \ 268272343Sngie if (opt_abort) \ 269272343Sngie abort(); \ 270272343Sngie } \ 271272343Sngie } \ 272272343Sngie} 273272343Sngie#elif (defined(_WIN32)) 274272343Sngie#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 275272343Sngie a_cleanup) \ 276272343Sngie/* Initialization/cleanup. */ \ 277272343Sngiea_attr bool \ 278272343Sngiea_name##tsd_cleanup_wrapper(void) \ 279272343Sngie{ \ 280272343Sngie DWORD error = GetLastError(); \ 281272343Sngie a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ 282272343Sngie TlsGetValue(a_name##tsd_tsd); \ 283272343Sngie SetLastError(error); \ 284272343Sngie \ 285272343Sngie if (wrapper == NULL) \ 286272343Sngie return (false); \ 287272343Sngie if (a_cleanup != malloc_tsd_no_cleanup && \ 288272343Sngie wrapper->initialized) { \ 289272343Sngie wrapper->initialized = false; \ 290272343Sngie a_cleanup(&wrapper->val); \ 291272343Sngie if (wrapper->initialized) { \ 292272343Sngie /* Trigger another cleanup round. */ \ 293272343Sngie return (true); \ 294272343Sngie } \ 295272343Sngie } \ 296272343Sngie malloc_tsd_dalloc(wrapper); \ 297272343Sngie return (false); \ 298272343Sngie} \ 299272343Sngiea_attr void \ 300272343Sngiea_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ 301272343Sngie{ \ 302272343Sngie \ 303272343Sngie if (!TlsSetValue(a_name##tsd_tsd, (void *)wrapper)) { \ 304272343Sngie malloc_write("<jemalloc>: Error setting" \ 305272343Sngie " TSD for "#a_name"\n"); \ 306272343Sngie abort(); \ 307272343Sngie } \ 308272343Sngie} \ 309272343Sngiea_attr a_name##tsd_wrapper_t * \ 310272343Sngiea_name##tsd_wrapper_get(void) \ 311272343Sngie{ \ 312272343Sngie DWORD error = GetLastError(); \ 313272343Sngie a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ 314272343Sngie TlsGetValue(a_name##tsd_tsd); \ 315272343Sngie SetLastError(error); \ 316272343Sngie \ 317272343Sngie if (unlikely(wrapper == NULL)) { \ 318272343Sngie wrapper = (a_name##tsd_wrapper_t *) \ 319272343Sngie malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ 320272343Sngie if (wrapper == NULL) { \ 321272343Sngie malloc_write("<jemalloc>: Error allocating" \ 322272343Sngie " TSD for "#a_name"\n"); \ 323272343Sngie abort(); \ 324272343Sngie } else { \ 325272343Sngie wrapper->initialized = false; \ 326272343Sngie wrapper->val = a_initializer; \ 327272343Sngie } \ 328272343Sngie a_name##tsd_wrapper_set(wrapper); \ 329272343Sngie } \ 330272343Sngie return (wrapper); \ 331272343Sngie} \ 332272343Sngiea_attr bool \ 333272343Sngiea_name##tsd_boot0(void) \ 334272343Sngie{ \ 335272343Sngie \ 336272343Sngie a_name##tsd_tsd = TlsAlloc(); \ 337272343Sngie if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) \ 338272343Sngie return (true); \ 339272343Sngie if (a_cleanup != malloc_tsd_no_cleanup) { \ 340272343Sngie malloc_tsd_cleanup_register( \ 341276478Sngie &a_name##tsd_cleanup_wrapper); \ 342272343Sngie } \ 343276478Sngie a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ 344272343Sngie a_name##tsd_booted = true; \ 345272343Sngie return (false); \ 346272343Sngie} \ 347272343Sngiea_attr void \ 348272343Sngiea_name##tsd_boot1(void) \ 349{ \ 350 a_name##tsd_wrapper_t *wrapper; \ 351 wrapper = (a_name##tsd_wrapper_t *) \ 352 malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ 353 if (wrapper == NULL) { \ 354 malloc_write("<jemalloc>: Error allocating" \ 355 " TSD for "#a_name"\n"); \ 356 abort(); \ 357 } \ 358 memcpy(wrapper, &a_name##tsd_boot_wrapper, \ 359 sizeof(a_name##tsd_wrapper_t)); \ 360 a_name##tsd_wrapper_set(wrapper); \ 361} \ 362a_attr bool \ 363a_name##tsd_boot(void) \ 364{ \ 365 \ 366 if (a_name##tsd_boot0()) \ 367 return (true); \ 368 a_name##tsd_boot1(); \ 369 return (false); \ 370} \ 371/* Get/set. */ \ 372a_attr a_type * \ 373a_name##tsd_get(void) \ 374{ \ 375 a_name##tsd_wrapper_t *wrapper; \ 376 \ 377 assert(a_name##tsd_booted); \ 378 wrapper = a_name##tsd_wrapper_get(); \ 379 return (&wrapper->val); \ 380} \ 381a_attr void \ 382a_name##tsd_set(a_type *val) \ 383{ \ 384 a_name##tsd_wrapper_t *wrapper; \ 385 \ 386 assert(a_name##tsd_booted); \ 387 wrapper = a_name##tsd_wrapper_get(); \ 388 wrapper->val = *(val); \ 389 if (a_cleanup != malloc_tsd_no_cleanup) \ 390 wrapper->initialized = true; \ 391} 392#else 393#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 394 a_cleanup) \ 395/* Initialization/cleanup. */ \ 396a_attr void \ 397a_name##tsd_cleanup_wrapper(void *arg) \ 398{ \ 399 a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *)arg; \ 400 \ 401 if (a_cleanup != malloc_tsd_no_cleanup && \ 402 wrapper->initialized) { \ 403 wrapper->initialized = false; \ 404 a_cleanup(&wrapper->val); \ 405 if (wrapper->initialized) { \ 406 /* Trigger another cleanup round. */ \ 407 if (pthread_setspecific(a_name##tsd_tsd, \ 408 (void *)wrapper)) { \ 409 malloc_write("<jemalloc>: Error" \ 410 " setting TSD for "#a_name"\n"); \ 411 if (opt_abort) \ 412 abort(); \ 413 } \ 414 return; \ 415 } \ 416 } \ 417 malloc_tsd_dalloc(wrapper); \ 418} \ 419a_attr void \ 420a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ 421{ \ 422 \ 423 if (pthread_setspecific(a_name##tsd_tsd, \ 424 (void *)wrapper)) { \ 425 malloc_write("<jemalloc>: Error setting" \ 426 " TSD for "#a_name"\n"); \ 427 abort(); \ 428 } \ 429} \ 430a_attr a_name##tsd_wrapper_t * \ 431a_name##tsd_wrapper_get(void) \ 432{ \ 433 a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ 434 pthread_getspecific(a_name##tsd_tsd); \ 435 \ 436 if (unlikely(wrapper == NULL)) { \ 437 tsd_init_block_t block; \ 438 wrapper = tsd_init_check_recursion( \ 439 &a_name##tsd_init_head, &block); \ 440 if (wrapper) \ 441 return (wrapper); \ 442 wrapper = (a_name##tsd_wrapper_t *) \ 443 malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ 444 block.data = wrapper; \ 445 if (wrapper == NULL) { \ 446 malloc_write("<jemalloc>: Error allocating" \ 447 " TSD for "#a_name"\n"); \ 448 abort(); \ 449 } else { \ 450 wrapper->initialized = false; \ 451 wrapper->val = a_initializer; \ 452 } \ 453 a_name##tsd_wrapper_set(wrapper); \ 454 tsd_init_finish(&a_name##tsd_init_head, &block); \ 455 } \ 456 return (wrapper); \ 457} \ 458a_attr bool \ 459a_name##tsd_boot0(void) \ 460{ \ 461 \ 462 if (pthread_key_create(&a_name##tsd_tsd, \ 463 a_name##tsd_cleanup_wrapper) != 0) \ 464 return (true); \ 465 a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ 466 a_name##tsd_booted = true; \ 467 return (false); \ 468} \ 469a_attr void \ 470a_name##tsd_boot1(void) \ 471{ \ 472 a_name##tsd_wrapper_t *wrapper; \ 473 wrapper = (a_name##tsd_wrapper_t *) \ 474 malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ 475 if (wrapper == NULL) { \ 476 malloc_write("<jemalloc>: Error allocating" \ 477 " TSD for "#a_name"\n"); \ 478 abort(); \ 479 } \ 480 memcpy(wrapper, &a_name##tsd_boot_wrapper, \ 481 sizeof(a_name##tsd_wrapper_t)); \ 482 a_name##tsd_wrapper_set(wrapper); \ 483} \ 484a_attr bool \ 485a_name##tsd_boot(void) \ 486{ \ 487 \ 488 if (a_name##tsd_boot0()) \ 489 return (true); \ 490 a_name##tsd_boot1(); \ 491 return (false); \ 492} \ 493/* Get/set. */ \ 494a_attr a_type * \ 495a_name##tsd_get(void) \ 496{ \ 497 a_name##tsd_wrapper_t *wrapper; \ 498 \ 499 assert(a_name##tsd_booted); \ 500 wrapper = a_name##tsd_wrapper_get(); \ 501 return (&wrapper->val); \ 502} \ 503a_attr void \ 504a_name##tsd_set(a_type *val) \ 505{ \ 506 a_name##tsd_wrapper_t *wrapper; \ 507 \ 508 assert(a_name##tsd_booted); \ 509 wrapper = a_name##tsd_wrapper_get(); \ 510 wrapper->val = *(val); \ 511 if (a_cleanup != malloc_tsd_no_cleanup) \ 512 wrapper->initialized = true; \ 513} 514#endif 515 516#endif /* JEMALLOC_H_TYPES */ 517/******************************************************************************/ 518#ifdef JEMALLOC_H_STRUCTS 519 520#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ 521 !defined(_WIN32)) 522struct tsd_init_block_s { 523 ql_elm(tsd_init_block_t) link; 524 pthread_t thread; 525 void *data; 526}; 527struct tsd_init_head_s { 528 ql_head(tsd_init_block_t) blocks; 529 malloc_mutex_t lock; 530}; 531#endif 532 533#define MALLOC_TSD \ 534/* O(name, type) */ \ 535 O(tcache, tcache_t *) \ 536 O(thread_allocated, uint64_t) \ 537 O(thread_deallocated, uint64_t) \ 538 O(prof_tdata, prof_tdata_t *) \ 539 O(arena, arena_t *) \ 540 O(arenas_tdata, arena_tdata_t *) \ 541 O(narenas_tdata, unsigned) \ 542 O(arenas_tdata_bypass, bool) \ 543 O(tcache_enabled, tcache_enabled_t) \ 544 O(quarantine, quarantine_t *) \ 545 546#define TSD_INITIALIZER { \ 547 tsd_state_uninitialized, \ 548 NULL, \ 549 0, \ 550 0, \ 551 NULL, \ 552 NULL, \ 553 NULL, \ 554 0, \ 555 false, \ 556 tcache_enabled_default, \ 557 NULL \ 558} 559 560struct tsd_s { 561 tsd_state_t state; 562#define O(n, t) \ 563 t n; 564MALLOC_TSD 565#undef O 566}; 567 568static const tsd_t tsd_initializer = TSD_INITIALIZER; 569 570malloc_tsd_types(, tsd_t) 571 572#endif /* JEMALLOC_H_STRUCTS */ 573/******************************************************************************/ 574#ifdef JEMALLOC_H_EXTERNS 575 576void *malloc_tsd_malloc(size_t size); 577void malloc_tsd_dalloc(void *wrapper); 578void malloc_tsd_no_cleanup(void *arg); 579void malloc_tsd_cleanup_register(bool (*f)(void)); 580bool malloc_tsd_boot0(void); 581void malloc_tsd_boot1(void); 582#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ 583 !defined(_WIN32)) 584void *tsd_init_check_recursion(tsd_init_head_t *head, 585 tsd_init_block_t *block); 586void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); 587#endif 588void tsd_cleanup(void *arg); 589 590#endif /* JEMALLOC_H_EXTERNS */ 591/******************************************************************************/ 592#ifdef JEMALLOC_H_INLINES 593 594#ifndef JEMALLOC_ENABLE_INLINE 595malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) 596 597tsd_t *tsd_fetch(void); 598bool tsd_nominal(tsd_t *tsd); 599#define O(n, t) \ 600t *tsd_##n##p_get(tsd_t *tsd); \ 601t tsd_##n##_get(tsd_t *tsd); \ 602void tsd_##n##_set(tsd_t *tsd, t n); 603MALLOC_TSD 604#undef O 605#endif 606 607#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) 608malloc_tsd_externs(, tsd_t) 609malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) 610 611JEMALLOC_ALWAYS_INLINE tsd_t * 612tsd_fetch(void) 613{ 614 tsd_t *tsd = tsd_get(); 615 616 if (unlikely(tsd->state != tsd_state_nominal)) { 617 if (tsd->state == tsd_state_uninitialized) { 618 tsd->state = tsd_state_nominal; 619 /* Trigger cleanup handler registration. */ 620 tsd_set(tsd); 621 } else if (tsd->state == tsd_state_purgatory) { 622 tsd->state = tsd_state_reincarnated; 623 tsd_set(tsd); 624 } else 625 assert(tsd->state == tsd_state_reincarnated); 626 } 627 628 return (tsd); 629} 630 631JEMALLOC_INLINE bool 632tsd_nominal(tsd_t *tsd) 633{ 634 635 return (tsd->state == tsd_state_nominal); 636} 637 638#define O(n, t) \ 639JEMALLOC_ALWAYS_INLINE t * \ 640tsd_##n##p_get(tsd_t *tsd) \ 641{ \ 642 \ 643 return (&tsd->n); \ 644} \ 645 \ 646JEMALLOC_ALWAYS_INLINE t \ 647tsd_##n##_get(tsd_t *tsd) \ 648{ \ 649 \ 650 return (*tsd_##n##p_get(tsd)); \ 651} \ 652 \ 653JEMALLOC_ALWAYS_INLINE void \ 654tsd_##n##_set(tsd_t *tsd, t n) \ 655{ \ 656 \ 657 assert(tsd->state == tsd_state_nominal); \ 658 tsd->n = n; \ 659} 660MALLOC_TSD 661#undef O 662#endif 663 664#endif /* JEMALLOC_H_INLINES */ 665/******************************************************************************/ 666