tsd.h revision 3cc1f1aa6981d6647aa01cec725fb2c134c1b0e9
1/******************************************************************************/ 2#ifdef JEMALLOC_H_TYPES 3 4/* Maximum number of malloc_tsd users with cleanup functions. */ 5#define MALLOC_TSD_CLEANUPS_MAX 8 6 7typedef struct malloc_tsd_cleanup_s malloc_tsd_cleanup_t; 8struct malloc_tsd_cleanup_s { 9 bool (*f)(void *); 10 void *arg; 11}; 12 13/* 14 * TLS/TSD-agnostic macro-based implementation of thread-specific data. There 15 * are four macros that support (at least) three use cases: file-private, 16 * library-private, and library-private inlined. Following is an example 17 * library-private tsd variable: 18 * 19 * In example.h: 20 * typedef struct { 21 * int x; 22 * int y; 23 * } example_t; 24 * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0}) 25 * malloc_tsd_protos(, example, example_t *) 26 * malloc_tsd_externs(example, example_t *) 27 * In example.c: 28 * malloc_tsd_data(, example, example_t *, EX_INITIALIZER) 29 * malloc_tsd_funcs(, example, example_t *, EX_INITIALIZER, 30 * example_tsd_cleanup) 31 * 32 * The result is a set of generated functions, e.g.: 33 * 34 * bool example_tsd_boot(void) {...} 35 * example_t **example_tsd_get() {...} 36 * void example_tsd_set(example_t **val) {...} 37 * 38 * Note that all of the functions deal in terms of (a_type *) rather than 39 * (a_type) so that it is possible to support non-pointer types (unlike 40 * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is 41 * cast to (void *). This means that the cleanup function needs to cast *and* 42 * dereference the function argument, e.g.: 43 * 44 * void 45 * example_tsd_cleanup(void *arg) 46 * { 47 * example_t *example = *(example_t **)arg; 48 * 49 * [...] 50 * if ([want the cleanup function to be called again]) { 51 * example_tsd_set(&example); 52 * } 53 * } 54 * 55 * If example_tsd_set() is called within example_tsd_cleanup(), it will be 56 * called again. This is similar to how pthreads TSD destruction works, except 57 * that pthreads only calls the cleanup function again if the value was set to 58 * non-NULL. 59 */ 60 61/* malloc_tsd_protos(). */ 62#define malloc_tsd_protos(a_attr, a_name, a_type) \ 63a_attr bool \ 64a_name##_tsd_boot(void); \ 65a_attr a_type * \ 66a_name##_tsd_get(void); \ 67a_attr void \ 68a_name##_tsd_set(a_type *val); 69 70/* malloc_tsd_externs(). */ 71#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 72#define malloc_tsd_externs(a_name, a_type) \ 73extern __thread a_type a_name##_tls; \ 74extern __thread bool a_name##_initialized; \ 75extern bool a_name##_booted; 76#elif (defined(JEMALLOC_TLS)) 77#define malloc_tsd_externs(a_name, a_type) \ 78extern __thread a_type a_name##_tls; \ 79extern pthread_key_t a_name##_tsd; \ 80extern bool a_name##_booted; 81#else 82#define malloc_tsd_externs(a_name, a_type) \ 83extern pthread_key_t a_name##_tsd; \ 84extern bool a_name##_booted; 85#endif 86 87/* malloc_tsd_data(). */ 88#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 89#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 90a_attr __thread a_type JEMALLOC_TLS_MODEL \ 91 a_name##_tls = a_initializer; \ 92a_attr __thread bool JEMALLOC_TLS_MODEL \ 93 a_name##_initialized = false; \ 94a_attr bool a_name##_booted = false; 95#elif (defined(JEMALLOC_TLS)) 96#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 97a_attr __thread a_type JEMALLOC_TLS_MODEL \ 98 a_name##_tls = a_initializer; \ 99a_attr pthread_key_t a_name##_tsd; \ 100a_attr bool a_name##_booted = false; 101#else 102#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ 103a_attr pthread_key_t a_name##_tsd; \ 104a_attr bool a_name##_booted = false; 105#endif 106 107/* malloc_tsd_funcs(). */ 108#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP 109#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 110 a_cleanup) \ 111/* Initialization/cleanup. */ \ 112a_attr bool \ 113a_name##_tsd_cleanup_wrapper(void *arg) \ 114{ \ 115 bool (*cleanup)(void *) = arg; \ 116 \ 117 if (a_name##_initialized) { \ 118 a_name##_initialized = false; \ 119 cleanup(&a_name##_tls); \ 120 } \ 121 return (a_name##_initialized); \ 122} \ 123a_attr bool \ 124a_name##_tsd_boot(void) \ 125{ \ 126 \ 127 if (a_cleanup != malloc_tsd_no_cleanup) { \ 128 malloc_tsd_cleanup_register( \ 129 &a_name##_tsd_cleanup_wrapper, a_cleanup); \ 130 } \ 131 a_name##_booted = true; \ 132 return (false); \ 133} \ 134/* Get/set. */ \ 135a_attr a_type * \ 136a_name##_tsd_get(void) \ 137{ \ 138 \ 139 assert(a_name##_booted); \ 140 return (&a_name##_tls); \ 141} \ 142a_attr void \ 143a_name##_tsd_set(a_type *val) \ 144{ \ 145 \ 146 assert(a_name##_booted); \ 147 a_name##_tls = (*val); \ 148 if (a_cleanup != malloc_tsd_no_cleanup) \ 149 a_name##_initialized = true; \ 150} 151#elif (defined(JEMALLOC_TLS)) 152#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 153 a_cleanup) \ 154/* Initialization/cleanup. */ \ 155a_attr bool \ 156a_name##_tsd_boot(void) \ 157{ \ 158 \ 159 if (a_cleanup != malloc_tsd_no_cleanup) { \ 160 if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0) \ 161 return (true); \ 162 } \ 163 a_name##_booted = true; \ 164 return (false); \ 165} \ 166/* Get/set. */ \ 167a_attr a_type * \ 168a_name##_tsd_get(void) \ 169{ \ 170 \ 171 assert(a_name##_booted); \ 172 return (&a_name##_tls); \ 173} \ 174a_attr void \ 175a_name##_tsd_set(a_type *val) \ 176{ \ 177 \ 178 assert(a_name##_booted); \ 179 a_name##_tls = (*val); \ 180 if (a_cleanup != malloc_tsd_no_cleanup) { \ 181 if (pthread_setspecific(a_name##_tsd, \ 182 (void *)(&a_name##_tls))) { \ 183 malloc_write("<jemalloc>: Error" \ 184 " setting TSD for "#a_name"\n"); \ 185 if (opt_abort) \ 186 abort(); \ 187 } \ 188 } \ 189} 190#else 191#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ 192 a_cleanup) \ 193/* Data structure. */ \ 194typedef struct { \ 195 bool isstatic; \ 196 bool initialized; \ 197 a_type val; \ 198} a_name##_tsd_wrapper_t; \ 199/* Initialization/cleanup. */ \ 200a_attr void \ 201a_name##_tsd_cleanup_wrapper(void *arg) \ 202{ \ 203 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\ 204 \ 205 if (a_cleanup != malloc_tsd_no_cleanup && \ 206 wrapper->initialized) { \ 207 wrapper->initialized = false; \ 208 a_cleanup(&wrapper->val); \ 209 if (wrapper->initialized) { \ 210 /* Trigger another cleanup round. */ \ 211 if (pthread_setspecific(a_name##_tsd, \ 212 (void *)wrapper)) { \ 213 malloc_write("<jemalloc>: Error" \ 214 " setting TSD for "#a_name"\n"); \ 215 if (opt_abort) \ 216 abort(); \ 217 } \ 218 return; \ 219 } \ 220 } \ 221 if (wrapper->isstatic == false) \ 222 malloc_tsd_dalloc(wrapper); \ 223} \ 224a_attr bool \ 225a_name##_tsd_boot(void) \ 226{ \ 227 \ 228 if (pthread_key_create(&a_name##_tsd, \ 229 a_name##_tsd_cleanup_wrapper) != 0) \ 230 return (true); \ 231 a_name##_booted = true; \ 232 return (false); \ 233} \ 234/* Get/set. */ \ 235a_attr a_name##_tsd_wrapper_t * \ 236a_name##_tsd_get_wrapper(void) \ 237{ \ 238 a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *) \ 239 pthread_getspecific(a_name##_tsd); \ 240 \ 241 if (wrapper == NULL) { \ 242 wrapper = (a_name##_tsd_wrapper_t *) \ 243 malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \ 244 if (wrapper == NULL) { \ 245 static a_name##_tsd_wrapper_t \ 246 a_name##_tsd_static_data = \ 247 {true, false, a_initializer}; \ 248 malloc_write("<jemalloc>: Error allocating" \ 249 " TSD for "#a_name"\n"); \ 250 if (opt_abort) \ 251 abort(); \ 252 wrapper = &a_name##_tsd_static_data; \ 253 } else { \ 254 static a_type tsd_static_data = a_initializer; \ 255 wrapper->isstatic = false; \ 256 wrapper->val = tsd_static_data; \ 257 } \ 258 if (pthread_setspecific(a_name##_tsd, \ 259 (void *)wrapper)) { \ 260 malloc_write("<jemalloc>: Error setting" \ 261 " TSD for "#a_name"\n"); \ 262 if (opt_abort) \ 263 abort(); \ 264 } \ 265 } \ 266 return (wrapper); \ 267} \ 268a_attr a_type * \ 269a_name##_tsd_get(void) \ 270{ \ 271 a_name##_tsd_wrapper_t *wrapper; \ 272 \ 273 assert(a_name##_booted); \ 274 wrapper = a_name##_tsd_get_wrapper(); \ 275 return (&wrapper->val); \ 276} \ 277a_attr void \ 278a_name##_tsd_set(a_type *val) \ 279{ \ 280 a_name##_tsd_wrapper_t *wrapper; \ 281 \ 282 assert(a_name##_booted); \ 283 wrapper = a_name##_tsd_get_wrapper(); \ 284 wrapper->val = *(val); \ 285 if (a_cleanup != malloc_tsd_no_cleanup) \ 286 wrapper->initialized = true; \ 287} 288#endif 289 290#endif /* JEMALLOC_H_TYPES */ 291/******************************************************************************/ 292#ifdef JEMALLOC_H_STRUCTS 293 294#endif /* JEMALLOC_H_STRUCTS */ 295/******************************************************************************/ 296#ifdef JEMALLOC_H_EXTERNS 297 298void *malloc_tsd_malloc(size_t size); 299void malloc_tsd_dalloc(void *wrapper); 300void malloc_tsd_no_cleanup(void *); 301void malloc_tsd_cleanup_register(bool (*f)(void *), void *arg); 302void malloc_tsd_boot(void); 303 304#endif /* JEMALLOC_H_EXTERNS */ 305/******************************************************************************/ 306#ifdef JEMALLOC_H_INLINES 307 308#endif /* JEMALLOC_H_INLINES */ 309/******************************************************************************/ 310