xref: /freebsd-src/contrib/jemalloc/include/jemalloc/internal/tsd_generic.h (revision c5ad81420c495d1d5de04209b0ec4fcb435c322c)
1b7eaed25SJason Evans #ifdef JEMALLOC_INTERNAL_TSD_GENERIC_H
2b7eaed25SJason Evans #error This file should be included only once, by tsd.h.
3b7eaed25SJason Evans #endif
4b7eaed25SJason Evans #define JEMALLOC_INTERNAL_TSD_GENERIC_H
5b7eaed25SJason Evans 
6b7eaed25SJason Evans typedef struct tsd_init_block_s tsd_init_block_t;
7b7eaed25SJason Evans struct tsd_init_block_s {
8b7eaed25SJason Evans 	ql_elm(tsd_init_block_t) link;
9b7eaed25SJason Evans 	pthread_t thread;
10b7eaed25SJason Evans 	void *data;
11b7eaed25SJason Evans };
12b7eaed25SJason Evans 
13b7eaed25SJason Evans /* Defined in tsd.c, to allow the mutex headers to have tsd dependencies. */
14b7eaed25SJason Evans typedef struct tsd_init_head_s tsd_init_head_t;
15b7eaed25SJason Evans 
16b7eaed25SJason Evans typedef struct {
17b7eaed25SJason Evans 	bool initialized;
18b7eaed25SJason Evans 	tsd_t val;
19b7eaed25SJason Evans } tsd_wrapper_t;
20b7eaed25SJason Evans 
21b7eaed25SJason Evans void *tsd_init_check_recursion(tsd_init_head_t *head,
22b7eaed25SJason Evans     tsd_init_block_t *block);
23b7eaed25SJason Evans void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block);
24b7eaed25SJason Evans 
25b7eaed25SJason Evans extern pthread_key_t tsd_tsd;
26b7eaed25SJason Evans extern tsd_init_head_t tsd_init_head;
27b7eaed25SJason Evans extern tsd_wrapper_t tsd_boot_wrapper;
28b7eaed25SJason Evans extern bool tsd_booted;
29b7eaed25SJason Evans 
30b7eaed25SJason Evans /* Initialization/cleanup. */
31b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE void
tsd_cleanup_wrapper(void * arg)32b7eaed25SJason Evans tsd_cleanup_wrapper(void *arg) {
33b7eaed25SJason Evans 	tsd_wrapper_t *wrapper = (tsd_wrapper_t *)arg;
34b7eaed25SJason Evans 
35b7eaed25SJason Evans 	if (wrapper->initialized) {
36b7eaed25SJason Evans 		wrapper->initialized = false;
37b7eaed25SJason Evans 		tsd_cleanup(&wrapper->val);
38b7eaed25SJason Evans 		if (wrapper->initialized) {
39b7eaed25SJason Evans 			/* Trigger another cleanup round. */
40b7eaed25SJason Evans 			if (pthread_setspecific(tsd_tsd, (void *)wrapper) != 0)
41b7eaed25SJason Evans 			{
42b7eaed25SJason Evans 				malloc_write("<jemalloc>: Error setting TSD\n");
43b7eaed25SJason Evans 				if (opt_abort) {
44b7eaed25SJason Evans 					abort();
45b7eaed25SJason Evans 				}
46b7eaed25SJason Evans 			}
47b7eaed25SJason Evans 			return;
48b7eaed25SJason Evans 		}
49b7eaed25SJason Evans 	}
50b7eaed25SJason Evans 	malloc_tsd_dalloc(wrapper);
51b7eaed25SJason Evans }
52b7eaed25SJason Evans 
53b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE void
tsd_wrapper_set(tsd_wrapper_t * wrapper)54b7eaed25SJason Evans tsd_wrapper_set(tsd_wrapper_t *wrapper) {
55b7eaed25SJason Evans 	if (pthread_setspecific(tsd_tsd, (void *)wrapper) != 0) {
56b7eaed25SJason Evans 		malloc_write("<jemalloc>: Error setting TSD\n");
57b7eaed25SJason Evans 		abort();
58b7eaed25SJason Evans 	}
59b7eaed25SJason Evans }
60b7eaed25SJason Evans 
61b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE tsd_wrapper_t *
tsd_wrapper_get(bool init)62b7eaed25SJason Evans tsd_wrapper_get(bool init) {
63b7eaed25SJason Evans 	tsd_wrapper_t *wrapper = (tsd_wrapper_t *)pthread_getspecific(tsd_tsd);
64b7eaed25SJason Evans 
65b7eaed25SJason Evans 	if (init && unlikely(wrapper == NULL)) {
66b7eaed25SJason Evans 		tsd_init_block_t block;
67b7eaed25SJason Evans 		wrapper = (tsd_wrapper_t *)
68b7eaed25SJason Evans 		    tsd_init_check_recursion(&tsd_init_head, &block);
69b7eaed25SJason Evans 		if (wrapper) {
70b7eaed25SJason Evans 			return wrapper;
71b7eaed25SJason Evans 		}
72b7eaed25SJason Evans 		wrapper = (tsd_wrapper_t *)
73b7eaed25SJason Evans 		    malloc_tsd_malloc(sizeof(tsd_wrapper_t));
74b7eaed25SJason Evans 		block.data = (void *)wrapper;
75b7eaed25SJason Evans 		if (wrapper == NULL) {
76b7eaed25SJason Evans 			malloc_write("<jemalloc>: Error allocating TSD\n");
77b7eaed25SJason Evans 			abort();
78b7eaed25SJason Evans 		} else {
79b7eaed25SJason Evans 			wrapper->initialized = false;
80*c5ad8142SEric van Gyzen       JEMALLOC_DIAGNOSTIC_PUSH
81*c5ad8142SEric van Gyzen       JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
82b7eaed25SJason Evans 			tsd_t initializer = TSD_INITIALIZER;
83*c5ad8142SEric van Gyzen       JEMALLOC_DIAGNOSTIC_POP
84b7eaed25SJason Evans 			wrapper->val = initializer;
85b7eaed25SJason Evans 		}
86b7eaed25SJason Evans 		tsd_wrapper_set(wrapper);
87b7eaed25SJason Evans 		tsd_init_finish(&tsd_init_head, &block);
88b7eaed25SJason Evans 	}
89b7eaed25SJason Evans 	return wrapper;
90b7eaed25SJason Evans }
91b7eaed25SJason Evans 
92b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool
tsd_boot0(void)93b7eaed25SJason Evans tsd_boot0(void) {
94b7eaed25SJason Evans 	if (pthread_key_create(&tsd_tsd, tsd_cleanup_wrapper) != 0) {
95b7eaed25SJason Evans 		return true;
96b7eaed25SJason Evans 	}
97b7eaed25SJason Evans 	tsd_wrapper_set(&tsd_boot_wrapper);
98b7eaed25SJason Evans 	tsd_booted = true;
99b7eaed25SJason Evans 	return false;
100b7eaed25SJason Evans }
101b7eaed25SJason Evans 
102b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE void
tsd_boot1(void)103b7eaed25SJason Evans tsd_boot1(void) {
104b7eaed25SJason Evans 	tsd_wrapper_t *wrapper;
105b7eaed25SJason Evans 	wrapper = (tsd_wrapper_t *)malloc_tsd_malloc(sizeof(tsd_wrapper_t));
106b7eaed25SJason Evans 	if (wrapper == NULL) {
107b7eaed25SJason Evans 		malloc_write("<jemalloc>: Error allocating TSD\n");
108b7eaed25SJason Evans 		abort();
109b7eaed25SJason Evans 	}
110b7eaed25SJason Evans 	tsd_boot_wrapper.initialized = false;
111b7eaed25SJason Evans 	tsd_cleanup(&tsd_boot_wrapper.val);
112b7eaed25SJason Evans 	wrapper->initialized = false;
113*c5ad8142SEric van Gyzen   JEMALLOC_DIAGNOSTIC_PUSH
114*c5ad8142SEric van Gyzen   JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
115b7eaed25SJason Evans 	tsd_t initializer = TSD_INITIALIZER;
116*c5ad8142SEric van Gyzen   JEMALLOC_DIAGNOSTIC_POP
117b7eaed25SJason Evans 	wrapper->val = initializer;
118b7eaed25SJason Evans 	tsd_wrapper_set(wrapper);
119b7eaed25SJason Evans }
120b7eaed25SJason Evans 
121b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool
tsd_boot(void)122b7eaed25SJason Evans tsd_boot(void) {
123b7eaed25SJason Evans 	if (tsd_boot0()) {
124b7eaed25SJason Evans 		return true;
125b7eaed25SJason Evans 	}
126b7eaed25SJason Evans 	tsd_boot1();
127b7eaed25SJason Evans 	return false;
128b7eaed25SJason Evans }
129b7eaed25SJason Evans 
130b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool
tsd_booted_get(void)131b7eaed25SJason Evans tsd_booted_get(void) {
132b7eaed25SJason Evans 	return tsd_booted;
133b7eaed25SJason Evans }
134b7eaed25SJason Evans 
135b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool
tsd_get_allocates(void)136b7eaed25SJason Evans tsd_get_allocates(void) {
137b7eaed25SJason Evans 	return true;
138b7eaed25SJason Evans }
139b7eaed25SJason Evans 
140b7eaed25SJason Evans /* Get/set. */
141b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE tsd_t *
tsd_get(bool init)142b7eaed25SJason Evans tsd_get(bool init) {
143b7eaed25SJason Evans 	tsd_wrapper_t *wrapper;
144b7eaed25SJason Evans 
145b7eaed25SJason Evans 	assert(tsd_booted);
146b7eaed25SJason Evans 	wrapper = tsd_wrapper_get(init);
147b7eaed25SJason Evans 	if (tsd_get_allocates() && !init && wrapper == NULL) {
148b7eaed25SJason Evans 		return NULL;
149b7eaed25SJason Evans 	}
150b7eaed25SJason Evans 	return &wrapper->val;
151b7eaed25SJason Evans }
152b7eaed25SJason Evans 
153b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE void
tsd_set(tsd_t * val)154b7eaed25SJason Evans tsd_set(tsd_t *val) {
155b7eaed25SJason Evans 	tsd_wrapper_t *wrapper;
156b7eaed25SJason Evans 
157b7eaed25SJason Evans 	assert(tsd_booted);
158b7eaed25SJason Evans 	wrapper = tsd_wrapper_get(true);
159b7eaed25SJason Evans 	if (likely(&wrapper->val != val)) {
160b7eaed25SJason Evans 		wrapper->val = *(val);
161b7eaed25SJason Evans 	}
162b7eaed25SJason Evans 	wrapper->initialized = true;
163b7eaed25SJason Evans }
164