Rizin
unix-like reverse engineering framework and cli tools
tsd.h
Go to the documentation of this file.
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 typedef struct tsdn_s tsdn_t;
17 
18 #define TSDN_NULL ((tsdn_t *)0)
19 
20 typedef enum {
21  tsd_state_uninitialized,
22  tsd_state_nominal,
23  tsd_state_purgatory,
24  tsd_state_reincarnated
25 } tsd_state_t;
26 
27 /*
28  * TLS/TSD-agnostic macro-based implementation of thread-specific data. There
29  * are five macros that support (at least) three use cases: file-private,
30  * library-private, and library-private inlined. Following is an example
31  * library-private tsd variable:
32  *
33  * In example.h:
34  * typedef struct {
35  * int x;
36  * int y;
37  * } example_t;
38  * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0})
39  * malloc_tsd_types(example_, example_t)
40  * malloc_tsd_protos(, example_, example_t)
41  * malloc_tsd_externs(example_, example_t)
42  * In example.c:
43  * malloc_tsd_data(, example_, example_t, EX_INITIALIZER)
44  * malloc_tsd_funcs(, example_, example_t, EX_INITIALIZER,
45  * example_tsd_cleanup)
46  *
47  * The result is a set of generated functions, e.g.:
48  *
49  * bool example_tsd_boot(void) {...}
50  * bool example_tsd_booted_get(void) {...}
51  * example_t *example_tsd_get(bool init) {...}
52  * void example_tsd_set(example_t *val) {...}
53  *
54  * Note that all of the functions deal in terms of (a_type *) rather than
55  * (a_type) so that it is possible to support non-pointer types (unlike
56  * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is
57  * cast to (void *). This means that the cleanup function needs to cast the
58  * function argument to (a_type *), then dereference the resulting pointer to
59  * access fields, e.g.
60  *
61  * void
62  * example_tsd_cleanup(void *arg)
63  * {
64  * example_t *example = (example_t *)arg;
65  *
66  * example->x = 42;
67  * [...]
68  * if ([want the cleanup function to be called again])
69  * example_tsd_set(example);
70  * }
71  *
72  * If example_tsd_set() is called within example_tsd_cleanup(), it will be
73  * called again. This is similar to how pthreads TSD destruction works, except
74  * that pthreads only calls the cleanup function again if the value was set to
75  * non-NULL.
76  */
77 
78 /* malloc_tsd_types(). */
79 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
80 #define malloc_tsd_types(a_name, a_type)
81 #elif (defined(JEMALLOC_TLS))
82 #define malloc_tsd_types(a_name, a_type)
83 #elif (defined(_WIN32))
84 #define malloc_tsd_types(a_name, a_type) \
85 typedef struct { \
86  bool initialized; \
87  a_type val; \
88 } a_name##tsd_wrapper_t;
89 #else
90 #define malloc_tsd_types(a_name, a_type) \
91 typedef struct { \
92  bool initialized; \
93  a_type val; \
94 } a_name##tsd_wrapper_t;
95 #endif
96 
97 /* malloc_tsd_protos(). */
98 #define malloc_tsd_protos(a_attr, a_name, a_type) \
99 a_attr bool \
100 a_name##tsd_boot0(void); \
101 a_attr void \
102 a_name##tsd_boot1(void); \
103 a_attr bool \
104 a_name##tsd_boot(void); \
105 a_attr bool \
106 a_name##tsd_booted_get(void); \
107 a_attr a_type * \
108 a_name##tsd_get(bool init); \
109 a_attr void \
110 a_name##tsd_set(a_type *val);
111 
112 /* malloc_tsd_externs(). */
113 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
114 #define malloc_tsd_externs(a_name, a_type) \
115 extern __thread a_type a_name##tsd_tls; \
116 extern __thread bool a_name##tsd_initialized; \
117 extern bool a_name##tsd_booted;
118 #elif (defined(JEMALLOC_TLS))
119 #define malloc_tsd_externs(a_name, a_type) \
120 extern __thread a_type a_name##tsd_tls; \
121 extern pthread_key_t a_name##tsd_tsd; \
122 extern bool a_name##tsd_booted;
123 #elif (defined(_WIN32))
124 #define malloc_tsd_externs(a_name, a_type) \
125 extern DWORD a_name##tsd_tsd; \
126 extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \
127 extern bool a_name##tsd_booted;
128 #else
129 #define malloc_tsd_externs(a_name, a_type) \
130 extern pthread_key_t a_name##tsd_tsd; \
131 extern tsd_init_head_t a_name##tsd_init_head; \
132 extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \
133 extern bool a_name##tsd_booted;
134 #endif
135 
136 /* malloc_tsd_data(). */
137 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
138 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
139 a_attr __thread a_type JEMALLOC_TLS_MODEL \
140  a_name##tsd_tls = a_initializer; \
141 a_attr __thread bool JEMALLOC_TLS_MODEL \
142  a_name##tsd_initialized = false; \
143 a_attr bool a_name##tsd_booted = false;
144 #elif (defined(JEMALLOC_TLS))
145 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
146 a_attr __thread a_type JEMALLOC_TLS_MODEL \
147  a_name##tsd_tls = a_initializer; \
148 a_attr pthread_key_t a_name##tsd_tsd; \
149 a_attr bool a_name##tsd_booted = false;
150 #elif (defined(_WIN32))
151 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
152 a_attr DWORD a_name##tsd_tsd; \
153 a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \
154  false, \
155  a_initializer \
156 }; \
157 a_attr bool a_name##tsd_booted = false;
158 #else
159 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
160 a_attr pthread_key_t a_name##tsd_tsd; \
161 a_attr tsd_init_head_t a_name##tsd_init_head = { \
162  ql_head_initializer(blocks), \
163  MALLOC_MUTEX_INITIALIZER \
164 }; \
165 a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \
166  false, \
167  a_initializer \
168 }; \
169 a_attr bool a_name##tsd_booted = false;
170 #endif
171 
172 /* malloc_tsd_funcs(). */
173 #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
174 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
175  a_cleanup) \
176 /* Initialization/cleanup. */ \
177 a_attr bool \
178 a_name##tsd_cleanup_wrapper(void) \
179 { \
180  \
181  if (a_name##tsd_initialized) { \
182  a_name##tsd_initialized = false; \
183  a_cleanup(&a_name##tsd_tls); \
184  } \
185  return (a_name##tsd_initialized); \
186 } \
187 a_attr bool \
188 a_name##tsd_boot0(void) \
189 { \
190  \
191  if (a_cleanup != malloc_tsd_no_cleanup) { \
192  malloc_tsd_cleanup_register( \
193  &a_name##tsd_cleanup_wrapper); \
194  } \
195  a_name##tsd_booted = true; \
196  return (false); \
197 } \
198 a_attr void \
199 a_name##tsd_boot1(void) \
200 { \
201  \
202  /* Do nothing. */ \
203 } \
204 a_attr bool \
205 a_name##tsd_boot(void) \
206 { \
207  \
208  return (a_name##tsd_boot0()); \
209 } \
210 a_attr bool \
211 a_name##tsd_booted_get(void) \
212 { \
213  \
214  return (a_name##tsd_booted); \
215 } \
216 a_attr bool \
217 a_name##tsd_get_allocates(void) \
218 { \
219  \
220  return (false); \
221 } \
222 /* Get/set. */ \
223 a_attr a_type * \
224 a_name##tsd_get(bool init) \
225 { \
226  \
227  assert(a_name##tsd_booted); \
228  return (&a_name##tsd_tls); \
229 } \
230 a_attr void \
231 a_name##tsd_set(a_type *val) \
232 { \
233  \
234  assert(a_name##tsd_booted); \
235  a_name##tsd_tls = (*val); \
236  if (a_cleanup != malloc_tsd_no_cleanup) \
237  a_name##tsd_initialized = true; \
238 }
239 #elif (defined(JEMALLOC_TLS))
240 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
241  a_cleanup) \
242 /* Initialization/cleanup. */ \
243 a_attr bool \
244 a_name##tsd_boot0(void) \
245 { \
246  \
247  if (a_cleanup != malloc_tsd_no_cleanup) { \
248  if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \
249  0) \
250  return (true); \
251  } \
252  a_name##tsd_booted = true; \
253  return (false); \
254 } \
255 a_attr void \
256 a_name##tsd_boot1(void) \
257 { \
258  \
259  /* Do nothing. */ \
260 } \
261 a_attr bool \
262 a_name##tsd_boot(void) \
263 { \
264  \
265  return (a_name##tsd_boot0()); \
266 } \
267 a_attr bool \
268 a_name##tsd_booted_get(void) \
269 { \
270  \
271  return (a_name##tsd_booted); \
272 } \
273 a_attr bool \
274 a_name##tsd_get_allocates(void) \
275 { \
276  \
277  return (false); \
278 } \
279 /* Get/set. */ \
280 a_attr a_type * \
281 a_name##tsd_get(bool init) \
282 { \
283  \
284  assert(a_name##tsd_booted); \
285  return (&a_name##tsd_tls); \
286 } \
287 a_attr void \
288 a_name##tsd_set(a_type *val) \
289 { \
290  \
291  assert(a_name##tsd_booted); \
292  a_name##tsd_tls = (*val); \
293  if (a_cleanup != malloc_tsd_no_cleanup) { \
294  if (pthread_setspecific(a_name##tsd_tsd, \
295  (void *)(&a_name##tsd_tls))) { \
296  malloc_write("<jemalloc>: Error" \
297  " setting TSD for "#a_name"\n"); \
298  if (opt_abort) \
299  abort(); \
300  } \
301  } \
302 }
303 #elif (defined(_WIN32))
304 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
305  a_cleanup) \
306 /* Initialization/cleanup. */ \
307 a_attr bool \
308 a_name##tsd_cleanup_wrapper(void) \
309 { \
310  DWORD error = GetLastError(); \
311  a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \
312  TlsGetValue(a_name##tsd_tsd); \
313  SetLastError(error); \
314  \
315  if (wrapper == NULL) \
316  return (false); \
317  if (a_cleanup != malloc_tsd_no_cleanup && \
318  wrapper->initialized) { \
319  wrapper->initialized = false; \
320  a_cleanup(&wrapper->val); \
321  if (wrapper->initialized) { \
322  /* Trigger another cleanup round. */ \
323  return (true); \
324  } \
325  } \
326  malloc_tsd_dalloc(wrapper); \
327  return (false); \
328 } \
329 a_attr void \
330 a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \
331 { \
332  \
333  if (!TlsSetValue(a_name##tsd_tsd, (void *)wrapper)) { \
334  malloc_write("<jemalloc>: Error setting" \
335  " TSD for "#a_name"\n"); \
336  abort(); \
337  } \
338 } \
339 a_attr a_name##tsd_wrapper_t * \
340 a_name##tsd_wrapper_get(bool init) \
341 { \
342  DWORD error = GetLastError(); \
343  a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \
344  TlsGetValue(a_name##tsd_tsd); \
345  SetLastError(error); \
346  \
347  if (init && unlikely(wrapper == NULL)) { \
348  wrapper = (a_name##tsd_wrapper_t *) \
349  malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
350  if (wrapper == NULL) { \
351  malloc_write("<jemalloc>: Error allocating" \
352  " TSD for "#a_name"\n"); \
353  abort(); \
354  } else { \
355  wrapper->initialized = false; \
356  wrapper->val = a_initializer; \
357  } \
358  a_name##tsd_wrapper_set(wrapper); \
359  } \
360  return (wrapper); \
361 } \
362 a_attr bool \
363 a_name##tsd_boot0(void) \
364 { \
365  \
366  a_name##tsd_tsd = TlsAlloc(); \
367  if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) \
368  return (true); \
369  if (a_cleanup != malloc_tsd_no_cleanup) { \
370  malloc_tsd_cleanup_register( \
371  &a_name##tsd_cleanup_wrapper); \
372  } \
373  a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \
374  a_name##tsd_booted = true; \
375  return (false); \
376 } \
377 a_attr void \
378 a_name##tsd_boot1(void) \
379 { \
380  a_name##tsd_wrapper_t *wrapper; \
381  wrapper = (a_name##tsd_wrapper_t *) \
382  malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
383  if (wrapper == NULL) { \
384  malloc_write("<jemalloc>: Error allocating" \
385  " TSD for "#a_name"\n"); \
386  abort(); \
387  } \
388  memcpy(wrapper, &a_name##tsd_boot_wrapper, \
389  sizeof(a_name##tsd_wrapper_t)); \
390  a_name##tsd_wrapper_set(wrapper); \
391 } \
392 a_attr bool \
393 a_name##tsd_boot(void) \
394 { \
395  \
396  if (a_name##tsd_boot0()) \
397  return (true); \
398  a_name##tsd_boot1(); \
399  return (false); \
400 } \
401 a_attr bool \
402 a_name##tsd_booted_get(void) \
403 { \
404  \
405  return (a_name##tsd_booted); \
406 } \
407 a_attr bool \
408 a_name##tsd_get_allocates(void) \
409 { \
410  \
411  return (true); \
412 } \
413 /* Get/set. */ \
414 a_attr a_type * \
415 a_name##tsd_get(bool init) \
416 { \
417  a_name##tsd_wrapper_t *wrapper; \
418  \
419  assert(a_name##tsd_booted); \
420  wrapper = a_name##tsd_wrapper_get(init); \
421  if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \
422  return (NULL); \
423  return (&wrapper->val); \
424 } \
425 a_attr void \
426 a_name##tsd_set(a_type *val) \
427 { \
428  a_name##tsd_wrapper_t *wrapper; \
429  \
430  assert(a_name##tsd_booted); \
431  wrapper = a_name##tsd_wrapper_get(true); \
432  wrapper->val = *(val); \
433  if (a_cleanup != malloc_tsd_no_cleanup) \
434  wrapper->initialized = true; \
435 }
436 #else
437 #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
438  a_cleanup) \
439 /* Initialization/cleanup. */ \
440 a_attr void \
441 a_name##tsd_cleanup_wrapper(void *arg) \
442 { \
443  a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *)arg; \
444  \
445  if (a_cleanup != malloc_tsd_no_cleanup && \
446  wrapper->initialized) { \
447  wrapper->initialized = false; \
448  a_cleanup(&wrapper->val); \
449  if (wrapper->initialized) { \
450  /* Trigger another cleanup round. */ \
451  if (pthread_setspecific(a_name##tsd_tsd, \
452  (void *)wrapper)) { \
453  malloc_write("<jemalloc>: Error" \
454  " setting TSD for "#a_name"\n"); \
455  if (opt_abort) \
456  abort(); \
457  } \
458  return; \
459  } \
460  } \
461  malloc_tsd_dalloc(wrapper); \
462 } \
463 a_attr void \
464 a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \
465 { \
466  \
467  if (pthread_setspecific(a_name##tsd_tsd, \
468  (void *)wrapper)) { \
469  malloc_write("<jemalloc>: Error setting" \
470  " TSD for "#a_name"\n"); \
471  abort(); \
472  } \
473 } \
474 a_attr a_name##tsd_wrapper_t * \
475 a_name##tsd_wrapper_get(bool init) \
476 { \
477  a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \
478  pthread_getspecific(a_name##tsd_tsd); \
479  \
480  if (init && unlikely(wrapper == NULL)) { \
481  tsd_init_block_t block; \
482  wrapper = (a_name##tsd_wrapper_t *) \
483  tsd_init_check_recursion(&a_name##tsd_init_head, \
484  &block); \
485  if (wrapper) \
486  return (wrapper); \
487  wrapper = (a_name##tsd_wrapper_t *) \
488  malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
489  block.data = (void *)wrapper; \
490  if (wrapper == NULL) { \
491  malloc_write("<jemalloc>: Error allocating" \
492  " TSD for "#a_name"\n"); \
493  abort(); \
494  } else { \
495  wrapper->initialized = false; \
496  wrapper->val = a_initializer; \
497  } \
498  a_name##tsd_wrapper_set(wrapper); \
499  tsd_init_finish(&a_name##tsd_init_head, &block); \
500  } \
501  return (wrapper); \
502 } \
503 a_attr bool \
504 a_name##tsd_boot0(void) \
505 { \
506  \
507  if (pthread_key_create(&a_name##tsd_tsd, \
508  a_name##tsd_cleanup_wrapper) != 0) \
509  return (true); \
510  a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \
511  a_name##tsd_booted = true; \
512  return (false); \
513 } \
514 a_attr void \
515 a_name##tsd_boot1(void) \
516 { \
517  a_name##tsd_wrapper_t *wrapper; \
518  wrapper = (a_name##tsd_wrapper_t *) \
519  malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \
520  if (wrapper == NULL) { \
521  malloc_write("<jemalloc>: Error allocating" \
522  " TSD for "#a_name"\n"); \
523  abort(); \
524  } \
525  memcpy(wrapper, &a_name##tsd_boot_wrapper, \
526  sizeof(a_name##tsd_wrapper_t)); \
527  a_name##tsd_wrapper_set(wrapper); \
528 } \
529 a_attr bool \
530 a_name##tsd_boot(void) \
531 { \
532  \
533  if (a_name##tsd_boot0()) \
534  return (true); \
535  a_name##tsd_boot1(); \
536  return (false); \
537 } \
538 a_attr bool \
539 a_name##tsd_booted_get(void) \
540 { \
541  \
542  return (a_name##tsd_booted); \
543 } \
544 a_attr bool \
545 a_name##tsd_get_allocates(void) \
546 { \
547  \
548  return (true); \
549 } \
550 /* Get/set. */ \
551 a_attr a_type * \
552 a_name##tsd_get(bool init) \
553 { \
554  a_name##tsd_wrapper_t *wrapper; \
555  \
556  assert(a_name##tsd_booted); \
557  wrapper = a_name##tsd_wrapper_get(init); \
558  if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \
559  return (NULL); \
560  return (&wrapper->val); \
561 } \
562 a_attr void \
563 a_name##tsd_set(a_type *val) \
564 { \
565  a_name##tsd_wrapper_t *wrapper; \
566  \
567 
568 
569 
570  assert(a_name##tsd_booted); \
571  wrapper = a_name##tsd_wrapper_get(true); \
572  wrapper->val = *(val); \
573  if (a_cleanup != malloc_tsd_no_cleanup) \
574  wrapper->initialized = true; \
575 }
576 #endif
577 
578 #endif /* JEMALLOC_H_TYPES */
579 /******************************************************************************/
580 #ifdef JEMALLOC_H_STRUCTS
581 
582 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
583  !defined(_WIN32))
584 struct tsd_init_block_s {
585  ql_elm(tsd_init_block_t) link;
586  pthread_t thread;
587  void *data;
588 };
589 struct tsd_init_head_s {
590  ql_head(tsd_init_block_t) blocks;
591  malloc_mutex_t lock;
592 };
593 #endif
594 
595 #define MALLOC_TSD \
596 /* O(name, type) */ \
597  O(tcache, tcache_t *) \
598  O(thread_allocated, uint64_t) \
599  O(thread_deallocated, uint64_t) \
600  O(prof_tdata, prof_tdata_t *) \
601  O(iarena, arena_t *) \
602  O(arena, arena_t *) \
603  O(arenas_tdata, arena_tdata_t *) \
604  O(narenas_tdata, unsigned) \
605  O(arenas_tdata_bypass, bool) \
606  O(tcache_enabled, tcache_enabled_t) \
607  O(quarantine, quarantine_t *) \
608  O(witnesses, witness_list_t) \
609  O(witness_fork, bool) \
610 
611 #define TSD_INITIALIZER { \
612  tsd_state_uninitialized, \
613  NULL, \
614  0, \
615  0, \
616  NULL, \
617  NULL, \
618  NULL, \
619  NULL, \
620  0, \
621  false, \
622  tcache_enabled_default, \
623  NULL, \
624  ql_head_initializer(witnesses), \
625  false \
626 }
627 
628 struct tsd_s {
629  tsd_state_t state;
630 #define O(n, t) \
631  t n;
632 MALLOC_TSD
633 #undef O
634 };
635 
636 /*
637  * Wrapper around tsd_t that makes it possible to avoid implicit conversion
638  * between tsd_t and tsdn_t, where tsdn_t is "nullable" and has to be
639  * explicitly converted to tsd_t, which is non-nullable.
640  */
641 struct tsdn_s {
642  tsd_t tsd;
643 };
644 
645 static const tsd_t tsd_initializer = TSD_INITIALIZER;
646 
647 malloc_tsd_types(, tsd_t)
648 
649 #endif /* JEMALLOC_H_STRUCTS */
650 /******************************************************************************/
651 #ifdef JEMALLOC_H_EXTERNS
652 
653 void *malloc_tsd_malloc(size_t size);
654 void malloc_tsd_dalloc(void *wrapper);
655 void malloc_tsd_no_cleanup(void *arg);
656 void malloc_tsd_cleanup_register(bool (*f)(void));
657 tsd_t *malloc_tsd_boot0(void);
658 void malloc_tsd_boot1(void);
659 #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
660  !defined(_WIN32))
661 void *tsd_init_check_recursion(tsd_init_head_t *head,
662  tsd_init_block_t *block);
663 void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block);
664 #endif
665 void tsd_cleanup(void *arg);
666 
667 #endif /* JEMALLOC_H_EXTERNS */
668 /******************************************************************************/
669 #ifdef JEMALLOC_H_INLINES
670 
671 #ifndef JEMALLOC_ENABLE_INLINE
672 malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t)
673 
674 tsd_t *tsd_fetch_impl(bool init);
675 tsd_t *tsd_fetch(void);
676 tsdn_t *tsd_tsdn(tsd_t *tsd);
677 bool tsd_nominal(tsd_t *tsd);
678 #define O(n, t) \
679 t *tsd_##n##p_get(tsd_t *tsd); \
680 t tsd_##n##_get(tsd_t *tsd); \
681 void tsd_##n##_set(tsd_t *tsd, t n);
682 MALLOC_TSD
683 #undef O
684 tsdn_t *tsdn_fetch(void);
685 bool tsdn_null(const tsdn_t *tsdn);
686 tsd_t *tsdn_tsd(tsdn_t *tsdn);
687 #endif
688 
689 #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_))
690 malloc_tsd_externs(, tsd_t)
691 malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup)
692 
694 tsd_fetch_impl(bool init)
695 {
696  tsd_t *tsd = tsd_get(init);
697 
698  if (!init && tsd_get_allocates() && tsd == NULL)
699  return (NULL);
700 
701  if (unlikely(tsd == NULL))
702  return (NULL)
703  if (unlikely(tsd->state != tsd_state_nominal)) {
704  if (tsd->state == tsd_state_uninitialized) {
705  tsd->state = tsd_state_nominal;
706  /* Trigger cleanup handler registration. */
707  tsd_set(tsd);
708  } else if (tsd->state == tsd_state_purgatory) {
709  tsd->state = tsd_state_reincarnated;
710  tsd_set(tsd);
711  } else {
712  if (unlikely(tsd->state != tsd_state_reincarnated))
713  return (NULL);
714  }
715  }
716 
717  return (tsd);
718 }
719 
721 tsd_fetch(void)
722 {
723 
724  return (tsd_fetch_impl(true));
725 }
726 
727 JEMALLOC_ALWAYS_INLINE tsdn_t *
728 tsd_tsdn(tsd_t *tsd)
729 {
730 
731  return ((tsdn_t *)tsd);
732 }
733 
734 JEMALLOC_INLINE bool
735 tsd_nominal(tsd_t *tsd)
736 {
737 
738  return (tsd->state == tsd_state_nominal);
739 }
740 
741 #define O(n, t) \
742 JEMALLOC_ALWAYS_INLINE t * \
743 tsd_##n##p_get(tsd_t *tsd) \
744 { \
745  \
746  return (&tsd->n); \
747 } \
748  \
749 JEMALLOC_ALWAYS_INLINE t \
750 tsd_##n##_get(tsd_t *tsd) \
751 { \
752  \
753  return (*tsd_##n##p_get(tsd)); \
754 } \
755  \
756 JEMALLOC_ALWAYS_INLINE void \
757 tsd_##n##_set(tsd_t *tsd, t n) \
758 { \
759  \
760  assert(tsd->state == tsd_state_nominal); \
761  tsd->n = n; \
762 }
763 MALLOC_TSD
764 #undef O
765 
766 JEMALLOC_ALWAYS_INLINE tsdn_t *
767 tsdn_fetch(void)
768 {
769 
770  if (!tsd_booted_get())
771  return (NULL);
772 
773  return (tsd_tsdn(tsd_fetch_impl(false)));
774 }
775 
777 tsdn_null(const tsdn_t *tsdn)
778 {
779 
780  return (tsdn == NULL);
781 }
782 
784 tsdn_tsd(tsdn_t *tsdn)
785 {
786  if (unlikely(tsdn_null(tsdn)))
787  return (NULL);
788  return (&tsdn->tsd);
789 }
790 #endif
791 
792 #endif /* JEMALLOC_H_INLINES */
793 /******************************************************************************/
ut16 val
Definition: armass64_const.h:6
#define NULL
Definition: cris-opc.c:27
static static fork const void static count static fd link
Definition: sflib.h:33
voidpf void uLong size
Definition: ioapi.h:138
#define JEMALLOC_ATTR(s)
Definition: jemalloc.h:149
#define JEMALLOC_INLINE
#define JEMALLOC_ALWAYS_INLINE
#define unlikely(expr)
Definition: lz4.c:177
assert(limit<=UINT32_MAX/2)
#define tsdn_fetch
#define tsd_fetch_impl
#define tsd_booted_get
#define malloc_tsd_no_cleanup
#define malloc_tsd_malloc
#define tsd_booted
#define malloc_tsd_dalloc
#define tsd_init_check_recursion
#define tsdn_null
#define tsd_cleanup
#define tsd_init_finish
#define malloc_tsd_boot0
#define malloc_tsd_boot1
#define tsd_tsdn
#define tsd_fetch
#define tsd_get
#define malloc_tsd_cleanup_register
#define tsd_nominal
#define tsd_set
#define tsd_wrapper_get
#define tsdn_tsd
#define tsd_get_allocates
#define ql_elm(a_type)
Definition: ql.h:9
#define ql_head(a_type)
Definition: ql.h:2
#define f(i)
Definition: sha256.c:46
Definition: dis.h:43
bool init
Definition: core.c:77
uint64_t blocks
Definition: list.c:104
#define bool
Definition: sysdefs.h:146
static void lock(volatile int *lk)
Definition: malloc.c:61