tsd.h revision 261071
1234370Sjasone/******************************************************************************/ 2234370Sjasone#ifdef JEMALLOC_H_TYPES 3234370Sjasone 4234370Sjasone/* Maximum number of malloc_tsd users with cleanup functions. */ 5234370Sjasone#define MALLOC_TSD_CLEANUPS_MAX 8 6234370Sjasone 7234543Sjasonetypedef bool (*malloc_tsd_cleanup_t)(void); 8234370Sjasone 9261071Sjasone#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ 10261071Sjasone !defined(_WIN32)) 11261071Sjasonetypedef struct tsd_init_block_s tsd_init_block_t; 12261071Sjasonetypedef struct tsd_init_head_s tsd_init_head_t; 13261071Sjasone#endif 14261071Sjasone 15234370Sjasone/* 16234370Sjasone * TLS/TSD-agnostic macro-based implementation of thread-specific data. There 17234370Sjasone * are four macros that support (at least) three use cases: file-private, 18234370Sjasone * library-private, and library-private inlined. Following is an example 19234370Sjasone * library-private tsd variable: 20234370Sjasone * 21234370Sjasone * In example.h: 22234370Sjasone * typedef struct { 23234370Sjasone * int x; 24234370Sjasone * int y; 25234370Sjasone * } example_t; 26234370Sjasone * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0}) 27234370Sjasone * malloc_tsd_protos(, example, example_t *) 28234370Sjasone * malloc_tsd_externs(example, example_t *) 29234370Sjasone * In example.c: 30234370Sjasone * malloc_tsd_data(, example, example_t *, EX_INITIALIZER) 31234370Sjasone * malloc_tsd_funcs(, example, example_t *, EX_INITIALIZER, 32234370Sjasone * example_tsd_cleanup) 33234370Sjasone * 34234370Sjasone * The result is a set of generated functions, e.g.: 35234370Sjasone * 36234370Sjasone * bool example_tsd_boot(void) {...} 37234370Sjasone * example_t **example_tsd_get() {...} 38234370Sjasone * void example_tsd_set(example_t **val) {...} 39234370Sjasone * 40234370Sjasone * Note that all of the functions deal in terms of (a_type *) rather than 41234370Sjasone * (a_type) so that it is possible to support non-pointer types (unlike 42234370Sjasone * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is 43234370Sjasone * cast to (void *). This means that the cleanup function needs to cast *and* 44234370Sjasone * dereference the function argument, e.g.: 45234370Sjasone * 46234370Sjasone * void 47234370Sjasone * example_tsd_cleanup(void *arg) 48234370Sjasone * { 49234370Sjasone * example_t *example = *(example_t **)arg; 50234370Sjasone * 51234370Sjasone * [...] 52234370Sjasone * if ([want the cleanup function to be called again]) { 53234370Sjasone * example_tsd_set(&example); 54234370Sjasone * } 55234370Sjasone * } 56234370Sjasone * 57234370Sjasone * If example_tsd_set() is called within example_tsd_cleanup(), it will be 58234370Sjasone * called again. This is similar to how pthreads TSD destruction works, except 59234370Sjasone * that pthreads only calls the cleanup function again if the value was set to 60234370Sjasone * non-NULL. 61234370Sjasone */ 62234370Sjasone 63234370Sjasone/* malloc_tsd_protos(). */ 64234370Sjasone#define malloc_tsd_protos(a_attr, a_name, a_type) \ 65234370Sjasonea_attr bool \ 66234370Sjasonea_name##_tsd_boot(void); \ 67234370Sjasonea_attr a_type * \ 68234370Sjasonea_name##_tsd_get(void); \ 69234370Sjasonea_attr void \ 70234370Sjasonea_name##_tsd_set(a_type *val); 71234370Sjasone 72234370Sjasone/* malloc_tsd_externs(). */ 73234370Sjasone#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 74234370Sjasone#define malloc_tsd_externs(a_name, a_type) \ 75234370Sjasoneextern __thread a_type a_name##_tls; \ 76234370Sjasoneextern __thread bool a_name##_initialized; \ 77234370Sjasoneextern bool a_name##_booted; 78234370Sjasone#elif (defined(JEMALLOC_TLS)) 79234370Sjasone#define malloc_tsd_externs(a_name, a_type) \ 80234370Sjasoneextern __thread a_type a_name##_tls; \ 81234370Sjasoneextern pthread_key_t a_name##_tsd; \ 82234370Sjasoneextern bool a_name##_booted; 83235238Sjasone#elif (defined(_WIN32)) 84261071Sjasone#define malloc_tsd_externs(a_name, a_type) \ 85235238Sjasoneextern DWORD a_name##_tsd; \ 86235238Sjasoneextern bool a_name##_booted; 87234370Sjasone#else 88234370Sjasone#define malloc_tsd_externs(a_name, a_type) \ 89234370Sjasoneextern pthread_key_t a_name##_tsd; \ 90261071Sjasoneextern tsd_init_head_t a_name##_tsd_init_head; \ 91234370Sjasoneextern bool a_name##_booted; 92234370Sjasone#endif 93234370Sjasone 94234370Sjasone/* malloc_tsd_data(). */ 95234370Sjasone#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 96234370Sjasone#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 97234370Sjasonea_attr __thread a_type JEMALLOC_TLS_MODEL \ 98234370Sjasone a_name##_tls = a_initializer; \ 99234370Sjasonea_attr __thread bool JEMALLOC_TLS_MODEL \ 100234370Sjasone a_name##_initialized = false; \ 101234370Sjasonea_attr bool a_name##_booted = false; 102234370Sjasone#elif (defined(JEMALLOC_TLS)) 103234370Sjasone#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 104234370Sjasonea_attr __thread a_type JEMALLOC_TLS_MODEL \ 105234370Sjasone a_name##_tls = a_initializer; \ 106234370Sjasonea_attr pthread_key_t a_name##_tsd; \ 107234370Sjasonea_attr bool a_name##_booted = false; 108235238Sjasone#elif (defined(_WIN32)) 109235238Sjasone#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 110235238Sjasonea_attr DWORD a_name##_tsd; \ 111235238Sjasonea_attr bool a_name##_booted = false; 112234370Sjasone#else 113234370Sjasone#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 114234370Sjasonea_attr pthread_key_t a_name##_tsd; \ 115261071Sjasonea_attr tsd_init_head_t a_name##_tsd_init_head = { \ 116261071Sjasone ql_head_initializer(blocks), \ 117261071Sjasone MALLOC_MUTEX_INITIALIZER \ 118261071Sjasone}; \ 119234370Sjasonea_attr bool a_name##_booted = false; 120234370Sjasone#endif 121234370Sjasone 122234370Sjasone/* malloc_tsd_funcs(). */ 123234370Sjasone#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 124234370Sjasone#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 125234370Sjasone a_cleanup) \ 126234370Sjasone/* Initialization/cleanup. */ \ 127234370Sjasonea_attr bool \ 128234543Sjasonea_name##_tsd_cleanup_wrapper(void) \ 129234370Sjasone{ \ 130234370Sjasone \ 131234370Sjasone if (a_name##_initialized) { \ 132234370Sjasone a_name##_initialized = false; \ 133234569Sjasone a_cleanup(&a_name##_tls); \ 134234370Sjasone } \ 135234370Sjasone return (a_name##_initialized); \ 136234370Sjasone} \ 137234370Sjasonea_attr bool \ 138234370Sjasonea_name##_tsd_boot(void) \ 139234370Sjasone{ \ 140234370Sjasone \ 141234370Sjasone if (a_cleanup != malloc_tsd_no_cleanup) { \ 142234370Sjasone malloc_tsd_cleanup_register( \ 143234543Sjasone &a_name##_tsd_cleanup_wrapper); \ 144234370Sjasone } \ 145234370Sjasone a_name##_booted = true; \ 146234370Sjasone return (false); \ 147234370Sjasone} \ 148234370Sjasone/* Get/set. */ \ 149234370Sjasonea_attr a_type * \ 150234370Sjasonea_name##_tsd_get(void) \ 151234370Sjasone{ \ 152234370Sjasone \ 153234370Sjasone assert(a_name##_booted); \ 154234370Sjasone return (&a_name##_tls); \ 155234370Sjasone} \ 156234370Sjasonea_attr void \ 157234370Sjasonea_name##_tsd_set(a_type *val) \ 158234370Sjasone{ \ 159234370Sjasone \ 160234370Sjasone assert(a_name##_booted); \ 161234370Sjasone a_name##_tls = (*val); \ 162234370Sjasone if (a_cleanup != malloc_tsd_no_cleanup) \ 163234370Sjasone a_name##_initialized = true; \ 164234370Sjasone} 165234370Sjasone#elif (defined(JEMALLOC_TLS)) 166234370Sjasone#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 167234370Sjasone a_cleanup) \ 168234370Sjasone/* Initialization/cleanup. */ \ 169234370Sjasonea_attr bool \ 170234370Sjasonea_name##_tsd_boot(void) \ 171234370Sjasone{ \ 172234370Sjasone \ 173234370Sjasone if (a_cleanup != malloc_tsd_no_cleanup) { \ 174234370Sjasone if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0) \ 175234370Sjasone return (true); \ 176234370Sjasone } \ 177234370Sjasone a_name##_booted = true; \ 178234370Sjasone return (false); \ 179234370Sjasone} \ 180234370Sjasone/* Get/set. */ \ 181234370Sjasonea_attr a_type * \ 182234370Sjasonea_name##_tsd_get(void) \ 183234370Sjasone{ \ 184234370Sjasone \ 185234370Sjasone assert(a_name##_booted); \ 186234370Sjasone return (&a_name##_tls); \ 187234370Sjasone} \ 188234370Sjasonea_attr void \ 189234370Sjasonea_name##_tsd_set(a_type *val) \ 190234370Sjasone{ \ 191234370Sjasone \ 192234370Sjasone assert(a_name##_booted); \ 193234370Sjasone a_name##_tls = (*val); \ 194234370Sjasone if (a_cleanup != malloc_tsd_no_cleanup) { \ 195234370Sjasone if (pthread_setspecific(a_name##_tsd, \ 196234370Sjasone (void *)(&a_name##_tls))) { \ 197234370Sjasone malloc_write("<jemalloc>: Error" \ 198234370Sjasone " setting TSD for "#a_name"\n"); \ 199234370Sjasone if (opt_abort) \ 200234370Sjasone abort(); \ 201234370Sjasone } \ 202234370Sjasone } \ 203234370Sjasone} 204235238Sjasone#elif (defined(_WIN32)) 205235238Sjasone#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 206235238Sjasone a_cleanup) \ 207235238Sjasone/* Data structure. */ \ 208235238Sjasonetypedef struct { \ 209235238Sjasone bool initialized; \ 210235238Sjasone a_type val; \ 211235238Sjasone} a_name##_tsd_wrapper_t; \ 212235238Sjasone/* Initialization/cleanup. */ \ 213235238Sjasonea_attr bool \ 214235238Sjasonea_name##_tsd_cleanup_wrapper(void) \ 215235238Sjasone{ \ 216235238Sjasone a_name##_tsd_wrapper_t *wrapper; \ 217235238Sjasone \ 218235238Sjasone wrapper = (a_name##_tsd_wrapper_t *) TlsGetValue(a_name##_tsd); \ 219235238Sjasone if (wrapper == NULL) \ 220235238Sjasone return (false); \ 221235238Sjasone if (a_cleanup != malloc_tsd_no_cleanup && \ 222235238Sjasone wrapper->initialized) { \ 223235238Sjasone a_type val = wrapper->val; \ 224235238Sjasone a_type tsd_static_data = a_initializer; \ 225235238Sjasone wrapper->initialized = false; \ 226235238Sjasone wrapper->val = tsd_static_data; \ 227235238Sjasone a_cleanup(&val); \ 228235238Sjasone if (wrapper->initialized) { \ 229235238Sjasone /* Trigger another cleanup round. */ \ 230235238Sjasone return (true); \ 231235238Sjasone } \ 232235238Sjasone } \ 233235238Sjasone malloc_tsd_dalloc(wrapper); \ 234235238Sjasone return (false); \ 235235238Sjasone} \ 236235238Sjasonea_attr bool \ 237235238Sjasonea_name##_tsd_boot(void) \ 238235238Sjasone{ \ 239235238Sjasone \ 240235238Sjasone a_name##_tsd = TlsAlloc(); \ 241235238Sjasone if (a_name##_tsd == TLS_OUT_OF_INDEXES) \ 242235238Sjasone return (true); \ 243235238Sjasone if (a_cleanup != malloc_tsd_no_cleanup) { \ 244235238Sjasone malloc_tsd_cleanup_register( \ 245235238Sjasone &a_name##_tsd_cleanup_wrapper); \ 246235238Sjasone } \ 247235238Sjasone a_name##_booted = true; \ 248235238Sjasone return (false); \ 249235238Sjasone} \ 250235238Sjasone/* Get/set. */ \ 251235238Sjasonea_attr a_name##_tsd_wrapper_t * \ 252235238Sjasonea_name##_tsd_get_wrapper(void) \ 253235238Sjasone{ \ 254235238Sjasone a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \ 255235238Sjasone TlsGetValue(a_name##_tsd); \ 256235238Sjasone \ 257235238Sjasone if (wrapper == NULL) { \ 258235238Sjasone wrapper = (a_name##_tsd_wrapper_t *) \ 259235238Sjasone malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \ 260235238Sjasone if (wrapper == NULL) { \ 261235238Sjasone malloc_write("<jemalloc>: Error allocating" \ 262235238Sjasone " TSD for "#a_name"\n"); \ 263235238Sjasone abort(); \ 264235238Sjasone } else { \ 265235238Sjasone static a_type tsd_static_data = a_initializer; \ 266235238Sjasone wrapper->initialized = false; \ 267235238Sjasone wrapper->val = tsd_static_data; \ 268235238Sjasone } \ 269235238Sjasone if (!TlsSetValue(a_name##_tsd, (void *)wrapper)) { \ 270235238Sjasone malloc_write("<jemalloc>: Error setting" \ 271235238Sjasone " TSD for "#a_name"\n"); \ 272235238Sjasone abort(); \ 273235238Sjasone } \ 274235238Sjasone } \ 275235238Sjasone return (wrapper); \ 276235238Sjasone} \ 277235238Sjasonea_attr a_type * \ 278235238Sjasonea_name##_tsd_get(void) \ 279235238Sjasone{ \ 280235238Sjasone a_name##_tsd_wrapper_t *wrapper; \ 281235238Sjasone \ 282235238Sjasone assert(a_name##_booted); \ 283235238Sjasone wrapper = a_name##_tsd_get_wrapper(); \ 284235238Sjasone return (&wrapper->val); \ 285235238Sjasone} \ 286235238Sjasonea_attr void \ 287235238Sjasonea_name##_tsd_set(a_type *val) \ 288235238Sjasone{ \ 289235238Sjasone a_name##_tsd_wrapper_t *wrapper; \ 290235238Sjasone \ 291235238Sjasone assert(a_name##_booted); \ 292235238Sjasone wrapper = a_name##_tsd_get_wrapper(); \ 293235238Sjasone wrapper->val = *(val); \ 294235238Sjasone if (a_cleanup != malloc_tsd_no_cleanup) \ 295235238Sjasone wrapper->initialized = true; \ 296235238Sjasone} 297234370Sjasone#else 298234370Sjasone#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 299234370Sjasone a_cleanup) \ 300234370Sjasone/* Data structure. */ \ 301234370Sjasonetypedef struct { \ 302234370Sjasone bool initialized; \ 303234370Sjasone a_type val; \ 304234370Sjasone} a_name##_tsd_wrapper_t; \ 305234370Sjasone/* Initialization/cleanup. */ \ 306234370Sjasonea_attr void \ 307234370Sjasonea_name##_tsd_cleanup_wrapper(void *arg) \ 308234370Sjasone{ \ 309234370Sjasone a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\ 310234370Sjasone \ 311234370Sjasone if (a_cleanup != malloc_tsd_no_cleanup && \ 312234370Sjasone wrapper->initialized) { \ 313234370Sjasone wrapper->initialized = false; \ 314234370Sjasone a_cleanup(&wrapper->val); \ 315234370Sjasone if (wrapper->initialized) { \ 316234370Sjasone /* Trigger another cleanup round. */ \ 317234370Sjasone if (pthread_setspecific(a_name##_tsd, \ 318234370Sjasone (void *)wrapper)) { \ 319234370Sjasone malloc_write("<jemalloc>: Error" \ 320234370Sjasone " setting TSD for "#a_name"\n"); \ 321234370Sjasone if (opt_abort) \ 322234370Sjasone abort(); \ 323234370Sjasone } \ 324234370Sjasone return; \ 325234370Sjasone } \ 326234370Sjasone } \ 327234543Sjasone malloc_tsd_dalloc(wrapper); \ 328234370Sjasone} \ 329234370Sjasonea_attr bool \ 330234370Sjasonea_name##_tsd_boot(void) \ 331234370Sjasone{ \ 332234370Sjasone \ 333234370Sjasone if (pthread_key_create(&a_name##_tsd, \ 334234370Sjasone a_name##_tsd_cleanup_wrapper) != 0) \ 335234370Sjasone return (true); \ 336234370Sjasone a_name##_booted = true; \ 337234370Sjasone return (false); \ 338234370Sjasone} \ 339234370Sjasone/* Get/set. */ \ 340234370Sjasonea_attr a_name##_tsd_wrapper_t * \ 341234370Sjasonea_name##_tsd_get_wrapper(void) \ 342234370Sjasone{ \ 343234370Sjasone a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \ 344234370Sjasone pthread_getspecific(a_name##_tsd); \ 345234370Sjasone \ 346234370Sjasone if (wrapper == NULL) { \ 347261071Sjasone tsd_init_block_t block; \ 348261071Sjasone wrapper = tsd_init_check_recursion( \ 349261071Sjasone &a_name##_tsd_init_head, &block); \ 350261071Sjasone if (wrapper) \ 351261071Sjasone return (wrapper); \ 352234370Sjasone wrapper = (a_name##_tsd_wrapper_t *) \ 353234370Sjasone malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \ 354261071Sjasone block.data = wrapper; \ 355234370Sjasone if (wrapper == NULL) { \ 356234370Sjasone malloc_write("<jemalloc>: Error allocating" \ 357234370Sjasone " TSD for "#a_name"\n"); \ 358234543Sjasone abort(); \ 359234370Sjasone } else { \ 360234370Sjasone static a_type tsd_static_data = a_initializer; \ 361234543Sjasone wrapper->initialized = false; \ 362234370Sjasone wrapper->val = tsd_static_data; \ 363234370Sjasone } \ 364234370Sjasone if (pthread_setspecific(a_name##_tsd, \ 365234370Sjasone (void *)wrapper)) { \ 366234370Sjasone malloc_write("<jemalloc>: Error setting" \ 367234370Sjasone " TSD for "#a_name"\n"); \ 368234543Sjasone abort(); \ 369234370Sjasone } \ 370261071Sjasone tsd_init_finish(&a_name##_tsd_init_head, &block); \ 371234370Sjasone } \ 372234370Sjasone return (wrapper); \ 373234370Sjasone} \ 374234370Sjasonea_attr a_type * \ 375234370Sjasonea_name##_tsd_get(void) \ 376234370Sjasone{ \ 377234370Sjasone a_name##_tsd_wrapper_t *wrapper; \ 378234370Sjasone \ 379234370Sjasone assert(a_name##_booted); \ 380234370Sjasone wrapper = a_name##_tsd_get_wrapper(); \ 381234370Sjasone return (&wrapper->val); \ 382234370Sjasone} \ 383234370Sjasonea_attr void \ 384234370Sjasonea_name##_tsd_set(a_type *val) \ 385234370Sjasone{ \ 386234370Sjasone a_name##_tsd_wrapper_t *wrapper; \ 387234370Sjasone \ 388234370Sjasone assert(a_name##_booted); \ 389234370Sjasone wrapper = a_name##_tsd_get_wrapper(); \ 390234370Sjasone wrapper->val = *(val); \ 391234370Sjasone if (a_cleanup != malloc_tsd_no_cleanup) \ 392234370Sjasone wrapper->initialized = true; \ 393234370Sjasone} 394234370Sjasone#endif 395234370Sjasone 396234370Sjasone#endif /* JEMALLOC_H_TYPES */ 397234370Sjasone/******************************************************************************/ 398234370Sjasone#ifdef JEMALLOC_H_STRUCTS 399234370Sjasone 400261071Sjasone#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ 401261071Sjasone !defined(_WIN32)) 402261071Sjasonestruct tsd_init_block_s { 403261071Sjasone ql_elm(tsd_init_block_t) link; 404261071Sjasone pthread_t thread; 405261071Sjasone void *data; 406261071Sjasone}; 407261071Sjasonestruct tsd_init_head_s { 408261071Sjasone ql_head(tsd_init_block_t) blocks; 409261071Sjasone malloc_mutex_t lock; 410261071Sjasone}; 411261071Sjasone#endif 412261071Sjasone 413234370Sjasone#endif /* JEMALLOC_H_STRUCTS */ 414234370Sjasone/******************************************************************************/ 415234370Sjasone#ifdef JEMALLOC_H_EXTERNS 416234370Sjasone 417234370Sjasonevoid *malloc_tsd_malloc(size_t size); 418234370Sjasonevoid malloc_tsd_dalloc(void *wrapper); 419234370Sjasonevoid malloc_tsd_no_cleanup(void *); 420234543Sjasonevoid malloc_tsd_cleanup_register(bool (*f)(void)); 421234370Sjasonevoid malloc_tsd_boot(void); 422261071Sjasone#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ 423261071Sjasone !defined(_WIN32)) 424261071Sjasonevoid *tsd_init_check_recursion(tsd_init_head_t *head, 425261071Sjasone tsd_init_block_t *block); 426261071Sjasonevoid tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); 427261071Sjasone#endif 428234370Sjasone 429234370Sjasone#endif /* JEMALLOC_H_EXTERNS */ 430234370Sjasone/******************************************************************************/ 431234370Sjasone#ifdef JEMALLOC_H_INLINES 432234370Sjasone 433234370Sjasone#endif /* JEMALLOC_H_INLINES */ 434234370Sjasone/******************************************************************************/ 435