]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/jemalloc/include/jemalloc/internal/tsd.h
Import jemalloc a8f8d7540d66ddee7337db80c92890916e1063ca (dev branch,
[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 8
6
7 typedef 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)                       \
59 a_attr bool                                                             \
60 a_name##_tsd_boot(void);                                                \
61 a_attr a_type *                                                         \
62 a_name##_tsd_get(void);                                                 \
63 a_attr void                                                             \
64 a_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)                              \
69 extern __thread a_type  a_name##_tls;                                   \
70 extern __thread bool    a_name##_initialized;                           \
71 extern bool             a_name##_booted;
72 #elif (defined(JEMALLOC_TLS))
73 #define malloc_tsd_externs(a_name, a_type)                              \
74 extern __thread a_type  a_name##_tls;                                   \
75 extern pthread_key_t    a_name##_tsd;                                   \
76 extern bool             a_name##_booted;
77 #else
78 #define malloc_tsd_externs(a_name, a_type)                              \
79 extern pthread_key_t    a_name##_tsd;                                   \
80 extern 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)          \
86 a_attr __thread a_type JEMALLOC_TLS_MODEL                               \
87     a_name##_tls = a_initializer;                                       \
88 a_attr __thread bool JEMALLOC_TLS_MODEL                                 \
89     a_name##_initialized = false;                                       \
90 a_attr bool             a_name##_booted = false;
91 #elif (defined(JEMALLOC_TLS))
92 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer)          \
93 a_attr __thread a_type JEMALLOC_TLS_MODEL                               \
94     a_name##_tls = a_initializer;                                       \
95 a_attr pthread_key_t    a_name##_tsd;                                   \
96 a_attr bool             a_name##_booted = false;
97 #else
98 #define malloc_tsd_data(a_attr, a_name, a_type, a_initializer)          \
99 a_attr pthread_key_t    a_name##_tsd;                                   \
100 a_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. */                                           \
108 a_attr bool                                                             \
109 a_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 }                                                                       \
118 a_attr bool                                                             \
119 a_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. */                                                          \
130 a_attr a_type *                                                         \
131 a_name##_tsd_get(void)                                                  \
132 {                                                                       \
133                                                                         \
134         assert(a_name##_booted);                                        \
135         return (&a_name##_tls);                                         \
136 }                                                                       \
137 a_attr void                                                             \
138 a_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. */                                           \
150 a_attr bool                                                             \
151 a_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. */                                                          \
162 a_attr a_type *                                                         \
163 a_name##_tsd_get(void)                                                  \
164 {                                                                       \
165                                                                         \
166         assert(a_name##_booted);                                        \
167         return (&a_name##_tls);                                         \
168 }                                                                       \
169 a_attr void                                                             \
170 a_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. */                                                   \
189 typedef struct {                                                        \
190         bool    initialized;                                            \
191         a_type  val;                                                    \
192 } a_name##_tsd_wrapper_t;                                               \
193 /* Initialization/cleanup. */                                           \
194 a_attr void                                                             \
195 a_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 }                                                                       \
217 a_attr bool                                                             \
218 a_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. */                                                          \
228 a_attr a_name##_tsd_wrapper_t *                                         \
229 a_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 }                                                                       \
255 a_attr a_type *                                                         \
256 a_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 }                                                                       \
264 a_attr void                                                             \
265 a_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
285 void    *malloc_tsd_malloc(size_t size);
286 void    malloc_tsd_dalloc(void *wrapper);
287 void    malloc_tsd_no_cleanup(void *);
288 void    malloc_tsd_cleanup_register(bool (*f)(void));
289 void    malloc_tsd_boot(void);
290
291 #endif /* JEMALLOC_H_EXTERNS */
292 /******************************************************************************/
293 #ifdef JEMALLOC_H_INLINES
294
295 #endif /* JEMALLOC_H_INLINES */
296 /******************************************************************************/