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