]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/jemalloc/include/jemalloc/internal/tsd.h
Update jemalloc to 4.1.0.
[FreeBSD/FreeBSD.git] / contrib / jemalloc / include / jemalloc / internal / tsd.h
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 /******************************************************************************/