1 /******************************************************************************/ 2 #ifdef JEMALLOC_H_TYPES 3 4 /* Maximum number of malloc_tsd users with cleanup functions. */ 5 #define MALLOC_TSD_CLEANUPS_MAX 2 6 7 typedef bool (*malloc_tsd_cleanup_t)(void); 8 9 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ 10 !defined(_WIN32)) 11 typedef struct tsd_init_block_s tsd_init_block_t; 12 typedef struct tsd_init_head_s tsd_init_head_t; 13 #endif 14 15 typedef struct tsd_s tsd_t; 16 17 typedef enum { 18 tsd_state_uninitialized, 19 tsd_state_nominal, 20 tsd_state_purgatory, 21 tsd_state_reincarnated 22 } tsd_state_t; 23 24 /* 25 * TLS/TSD-agnostic macro-based implementation of thread-specific data. There 26 * are five macros that support (at least) three use cases: file-private, 27 * library-private, and library-private inlined. Following is an example 28 * library-private tsd variable: 29 * 30 * In example.h: 31 * typedef struct { 32 * int x; 33 * int y; 34 * } example_t; 35 * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0}) 36 * malloc_tsd_types(example_, example_t) 37 * malloc_tsd_protos(, example_, example_t) 38 * malloc_tsd_externs(example_, example_t) 39 * In example.c: 40 * malloc_tsd_data(, example_, example_t, EX_INITIALIZER) 41 * malloc_tsd_funcs(, example_, example_t, EX_INITIALIZER, 42 * example_tsd_cleanup) 43 * 44 * The result is a set of generated functions, e.g.: 45 * 46 * bool example_tsd_boot(void) {...} 47 * example_t *example_tsd_get() {...} 48 * void example_tsd_set(example_t *val) {...} 49 * 50 * Note that all of the functions deal in terms of (a_type *) rather than 51 * (a_type) so that it is possible to support non-pointer types (unlike 52 * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is 53 * cast to (void *). This means that the cleanup function needs to cast the 54 * function argument to (a_type *), then dereference the resulting pointer to 55 * access fields, e.g. 56 * 57 * void 58 * example_tsd_cleanup(void *arg) 59 * { 60 * example_t *example = (example_t *)arg; 61 * 62 * example->x = 42; 63 * [...] 64 * if ([want the cleanup function to be called again]) 65 * example_tsd_set(example); 66 * } 67 * 68 * If example_tsd_set() is called within example_tsd_cleanup(), it will be 69 * called again. This is similar to how pthreads TSD destruction works, except 70 * that pthreads only calls the cleanup function again if the value was set to 71 * non-NULL. 72 */ 73 74 /* malloc_tsd_types(). */ 75 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 76 #define malloc_tsd_types(a_name, a_type) 77 #elif (defined(JEMALLOC_TLS)) 78 #define malloc_tsd_types(a_name, a_type) 79 #elif (defined(_WIN32)) 80 #define malloc_tsd_types(a_name, a_type) \ 81 typedef struct { \ 82 bool initialized; \ 83 a_type val; \ 84 } a_name##tsd_wrapper_t; 85 #else 86 #define malloc_tsd_types(a_name, a_type) \ 87 typedef struct { \ 88 bool initialized; \ 89 a_type val; \ 90 } a_name##tsd_wrapper_t; 91 #endif 92 93 /* malloc_tsd_protos(). */ 94 #define malloc_tsd_protos(a_attr, a_name, a_type) \ 95 a_attr bool \ 96 a_name##tsd_boot0(void); \ 97 a_attr void \ 98 a_name##tsd_boot1(void); \ 99 a_attr bool \ 100 a_name##tsd_boot(void); \ 101 a_attr a_type * \ 102 a_name##tsd_get(void); \ 103 a_attr void \ 104 a_name##tsd_set(a_type *val); 105 106 /* malloc_tsd_externs(). */ 107 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 108 #define malloc_tsd_externs(a_name, a_type) \ 109 extern __thread a_type a_name##tsd_tls; \ 110 extern __thread bool a_name##tsd_initialized; \ 111 extern bool a_name##tsd_booted; 112 #elif (defined(JEMALLOC_TLS)) 113 #define malloc_tsd_externs(a_name, a_type) \ 114 extern __thread a_type a_name##tsd_tls; \ 115 extern pthread_key_t a_name##tsd_tsd; \ 116 extern bool a_name##tsd_booted; 117 #elif (defined(_WIN32)) 118 #define malloc_tsd_externs(a_name, a_type) \ 119 extern DWORD a_name##tsd_tsd; \ 120 extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ 121 extern bool a_name##tsd_booted; 122 #else 123 #define malloc_tsd_externs(a_name, a_type) \ 124 extern pthread_key_t a_name##tsd_tsd; \ 125 extern tsd_init_head_t a_name##tsd_init_head; \ 126 extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ 127 extern bool a_name##tsd_booted; 128 #endif 129 130 /* malloc_tsd_data(). */ 131 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 132 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 133 a_attr __thread a_type JEMALLOC_TLS_MODEL \ 134 a_name##tsd_tls = a_initializer; \ 135 a_attr __thread bool JEMALLOC_TLS_MODEL \ 136 a_name##tsd_initialized = false; \ 137 a_attr bool a_name##tsd_booted = false; 138 #elif (defined(JEMALLOC_TLS)) 139 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 140 a_attr __thread a_type JEMALLOC_TLS_MODEL \ 141 a_name##tsd_tls = a_initializer; \ 142 a_attr pthread_key_t a_name##tsd_tsd; \ 143 a_attr bool a_name##tsd_booted = false; 144 #elif (defined(_WIN32)) 145 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 146 a_attr DWORD a_name##tsd_tsd; \ 147 a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ 148 false, \ 149 a_initializer \ 150 }; \ 151 a_attr bool a_name##tsd_booted = false; 152 #else 153 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 154 a_attr pthread_key_t a_name##tsd_tsd; \ 155 a_attr tsd_init_head_t a_name##tsd_init_head = { \ 156 ql_head_initializer(blocks), \ 157 MALLOC_MUTEX_INITIALIZER \ 158 }; \ 159 a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ 160 false, \ 161 a_initializer \ 162 }; \ 163 a_attr bool a_name##tsd_booted = false; 164 #endif 165 166 /* malloc_tsd_funcs(). */ 167 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 168 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 169 a_cleanup) \ 170 /* Initialization/cleanup. */ \ 171 a_attr bool \ 172 a_name##tsd_cleanup_wrapper(void) \ 173 { \ 174 \ 175 if (a_name##tsd_initialized) { \ 176 a_name##tsd_initialized = false; \ 177 a_cleanup(&a_name##tsd_tls); \ 178 } \ 179 return (a_name##tsd_initialized); \ 180 } \ 181 a_attr bool \ 182 a_name##tsd_boot0(void) \ 183 { \ 184 \ 185 if (a_cleanup != malloc_tsd_no_cleanup) { \ 186 malloc_tsd_cleanup_register( \ 187 &a_name##tsd_cleanup_wrapper); \ 188 } \ 189 a_name##tsd_booted = true; \ 190 return (false); \ 191 } \ 192 a_attr void \ 193 a_name##tsd_boot1(void) \ 194 { \ 195 \ 196 /* Do nothing. */ \ 197 } \ 198 a_attr bool \ 199 a_name##tsd_boot(void) \ 200 { \ 201 \ 202 return (a_name##tsd_boot0()); \ 203 } \ 204 /* Get/set. */ \ 205 a_attr a_type * \ 206 a_name##tsd_get(void) \ 207 { \ 208 \ 209 assert(a_name##tsd_booted); \ 210 return (&a_name##tsd_tls); \ 211 } \ 212 a_attr void \ 213 a_name##tsd_set(a_type *val) \ 214 { \ 215 \ 216 assert(a_name##tsd_booted); \ 217 a_name##tsd_tls = (*val); \ 218 if (a_cleanup != malloc_tsd_no_cleanup) \ 219 a_name##tsd_initialized = true; \ 220 } 221 #elif (defined(JEMALLOC_TLS)) 222 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 223 a_cleanup) \ 224 /* Initialization/cleanup. */ \ 225 a_attr bool \ 226 a_name##tsd_boot0(void) \ 227 { \ 228 \ 229 if (a_cleanup != malloc_tsd_no_cleanup) { \ 230 if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \ 231 0) \ 232 return (true); \ 233 } \ 234 a_name##tsd_booted = true; \ 235 return (false); \ 236 } \ 237 a_attr void \ 238 a_name##tsd_boot1(void) \ 239 { \ 240 \ 241 /* Do nothing. */ \ 242 } \ 243 a_attr bool \ 244 a_name##tsd_boot(void) \ 245 { \ 246 \ 247 return (a_name##tsd_boot0()); \ 248 } \ 249 /* Get/set. */ \ 250 a_attr a_type * \ 251 a_name##tsd_get(void) \ 252 { \ 253 \ 254 assert(a_name##tsd_booted); \ 255 return (&a_name##tsd_tls); \ 256 } \ 257 a_attr void \ 258 a_name##tsd_set(a_type *val) \ 259 { \ 260 \ 261 assert(a_name##tsd_booted); \ 262 a_name##tsd_tls = (*val); \ 263 if (a_cleanup != malloc_tsd_no_cleanup) { \ 264 if (pthread_setspecific(a_name##tsd_tsd, \ 265 (void *)(&a_name##tsd_tls))) { \ 266 malloc_write("<jemalloc>: Error" \ 267 " setting TSD for "#a_name"\n"); \ 268 if (opt_abort) \ 269 abort(); \ 270 } \ 271 } \ 272 } 273 #elif (defined(_WIN32)) 274 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 275 a_cleanup) \ 276 /* Initialization/cleanup. */ \ 277 a_attr bool \ 278 a_name##tsd_cleanup_wrapper(void) \ 279 { \ 280 DWORD error = GetLastError(); \ 281 a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ 282 TlsGetValue(a_name##tsd_tsd); \ 283 SetLastError(error); \ 284 \ 285 if (wrapper == NULL) \ 286 return (false); \ 287 if (a_cleanup != malloc_tsd_no_cleanup && \ 288 wrapper->initialized) { \ 289 wrapper->initialized = false; \ 290 a_cleanup(&wrapper->val); \ 291 if (wrapper->initialized) { \ 292 /* Trigger another cleanup round. */ \ 293 return (true); \ 294 } \ 295 } \ 296 malloc_tsd_dalloc(wrapper); \ 297 return (false); \ 298 } \ 299 a_attr void \ 300 a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ 301 { \ 302 \ 303 if (!TlsSetValue(a_name##tsd_tsd, (void *)wrapper)) { \ 304 malloc_write("<jemalloc>: Error setting" \ 305 " TSD for "#a_name"\n"); \ 306 abort(); \ 307 } \ 308 } \ 309 a_attr a_name##tsd_wrapper_t * \ 310 a_name##tsd_wrapper_get(void) \ 311 { \ 312 DWORD error = GetLastError(); \ 313 a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ 314 TlsGetValue(a_name##tsd_tsd); \ 315 SetLastError(error); \ 316 \ 317 if (unlikely(wrapper == NULL)) { \ 318 wrapper = (a_name##tsd_wrapper_t *) \ 319 malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ 320 if (wrapper == NULL) { \ 321 malloc_write("<jemalloc>: Error allocating" \ 322 " TSD for "#a_name"\n"); \ 323 abort(); \ 324 } else { \ 325 wrapper->initialized = false; \ 326 wrapper->val = a_initializer; \ 327 } \ 328 a_name##tsd_wrapper_set(wrapper); \ 329 } \ 330 return (wrapper); \ 331 } \ 332 a_attr bool \ 333 a_name##tsd_boot0(void) \ 334 { \ 335 \ 336 a_name##tsd_tsd = TlsAlloc(); \ 337 if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) \ 338 return (true); \ 339 if (a_cleanup != malloc_tsd_no_cleanup) { \ 340 malloc_tsd_cleanup_register( \ 341 &a_name##tsd_cleanup_wrapper); \ 342 } \ 343 a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ 344 a_name##tsd_booted = true; \ 345 return (false); \ 346 } \ 347 a_attr void \ 348 a_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 } \ 362 a_attr bool \ 363 a_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. */ \ 372 a_attr a_type * \ 373 a_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 } \ 381 a_attr void \ 382 a_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. */ \ 396 a_attr void \ 397 a_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 } \ 419 a_attr void \ 420 a_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 } \ 430 a_attr a_name##tsd_wrapper_t * \ 431 a_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 } \ 458 a_attr bool \ 459 a_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 } \ 469 a_attr void \ 470 a_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 } \ 484 a_attr bool \ 485 a_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. */ \ 494 a_attr a_type * \ 495 a_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 } \ 503 a_attr void \ 504 a_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)) 522 struct tsd_init_block_s { 523 ql_elm(tsd_init_block_t) link; 524 pthread_t thread; 525 void *data; 526 }; 527 struct 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 560 struct tsd_s { 561 tsd_state_t state; 562 #define O(n, t) \ 563 t n; 564 MALLOC_TSD 565 #undef O 566 }; 567 568 static const tsd_t tsd_initializer = TSD_INITIALIZER; 569 570 malloc_tsd_types(, tsd_t) 571 572 #endif /* JEMALLOC_H_STRUCTS */ 573 /******************************************************************************/ 574 #ifdef JEMALLOC_H_EXTERNS 575 576 void *malloc_tsd_malloc(size_t size); 577 void malloc_tsd_dalloc(void *wrapper); 578 void malloc_tsd_no_cleanup(void *arg); 579 void malloc_tsd_cleanup_register(bool (*f)(void)); 580 bool malloc_tsd_boot0(void); 581 void malloc_tsd_boot1(void); 582 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ 583 !defined(_WIN32)) 584 void *tsd_init_check_recursion(tsd_init_head_t *head, 585 tsd_init_block_t *block); 586 void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); 587 #endif 588 void tsd_cleanup(void *arg); 589 590 #endif /* JEMALLOC_H_EXTERNS */ 591 /******************************************************************************/ 592 #ifdef JEMALLOC_H_INLINES 593 594 #ifndef JEMALLOC_ENABLE_INLINE 595 malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) 596 597 tsd_t *tsd_fetch(void); 598 bool tsd_nominal(tsd_t *tsd); 599 #define O(n, t) \ 600 t *tsd_##n##p_get(tsd_t *tsd); \ 601 t tsd_##n##_get(tsd_t *tsd); \ 602 void tsd_##n##_set(tsd_t *tsd, t n); 603 MALLOC_TSD 604 #undef O 605 #endif 606 607 #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) 608 malloc_tsd_externs(, tsd_t) 609 malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) 610 611 JEMALLOC_ALWAYS_INLINE tsd_t * 612 tsd_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 631 JEMALLOC_INLINE bool 632 tsd_nominal(tsd_t *tsd) 633 { 634 635 return (tsd->state == tsd_state_nominal); 636 } 637 638 #define O(n, t) \ 639 JEMALLOC_ALWAYS_INLINE t * \ 640 tsd_##n##p_get(tsd_t *tsd) \ 641 { \ 642 \ 643 return (&tsd->n); \ 644 } \ 645 \ 646 JEMALLOC_ALWAYS_INLINE t \ 647 tsd_##n##_get(tsd_t *tsd) \ 648 { \ 649 \ 650 return (*tsd_##n##p_get(tsd)); \ 651 } \ 652 \ 653 JEMALLOC_ALWAYS_INLINE void \ 654 tsd_##n##_set(tsd_t *tsd, t n) \ 655 { \ 656 \ 657 assert(tsd->state == tsd_state_nominal); \ 658 tsd->n = n; \ 659 } 660 MALLOC_TSD 661 #undef O 662 #endif 663 664 #endif /* JEMALLOC_H_INLINES */ 665 /******************************************************************************/ 666