tsd.h revision 235238
1234370Sjasone/******************************************************************************/
2234370Sjasone#ifdef JEMALLOC_H_TYPES
3234370Sjasone
4234370Sjasone/* Maximum number of malloc_tsd users with cleanup functions. */
5234370Sjasone#define	MALLOC_TSD_CLEANUPS_MAX	8
6234370Sjasone
7234543Sjasonetypedef bool (*malloc_tsd_cleanup_t)(void);
8234370Sjasone
9234370Sjasone/*
10234370Sjasone * TLS/TSD-agnostic macro-based implementation of thread-specific data.  There
11234370Sjasone * are four macros that support (at least) three use cases: file-private,
12234370Sjasone * library-private, and library-private inlined.  Following is an example
13234370Sjasone * library-private tsd variable:
14234370Sjasone *
15234370Sjasone * In example.h:
16234370Sjasone *   typedef struct {
17234370Sjasone *           int x;
18234370Sjasone *           int y;
19234370Sjasone *   } example_t;
20234370Sjasone *   #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0})
21234370Sjasone *   malloc_tsd_protos(, example, example_t *)
22234370Sjasone *   malloc_tsd_externs(example, example_t *)
23234370Sjasone * In example.c:
24234370Sjasone *   malloc_tsd_data(, example, example_t *, EX_INITIALIZER)
25234370Sjasone *   malloc_tsd_funcs(, example, example_t *, EX_INITIALIZER,
26234370Sjasone *       example_tsd_cleanup)
27234370Sjasone *
28234370Sjasone * The result is a set of generated functions, e.g.:
29234370Sjasone *
30234370Sjasone *   bool example_tsd_boot(void) {...}
31234370Sjasone *   example_t **example_tsd_get() {...}
32234370Sjasone *   void example_tsd_set(example_t **val) {...}
33234370Sjasone *
34234370Sjasone * Note that all of the functions deal in terms of (a_type *) rather than
35234370Sjasone * (a_type)  so that it is possible to support non-pointer types (unlike
36234370Sjasone * pthreads TSD).  example_tsd_cleanup() is passed an (a_type *) pointer that is
37234370Sjasone * cast to (void *).  This means that the cleanup function needs to cast *and*
38234370Sjasone * dereference the function argument, e.g.:
39234370Sjasone *
40234370Sjasone *   void
41234370Sjasone *   example_tsd_cleanup(void *arg)
42234370Sjasone *   {
43234370Sjasone *           example_t *example = *(example_t **)arg;
44234370Sjasone *
45234370Sjasone *           [...]
46234370Sjasone *           if ([want the cleanup function to be called again]) {
47234370Sjasone *                   example_tsd_set(&example);
48234370Sjasone *           }
49234370Sjasone *   }
50234370Sjasone *
51234370Sjasone * If example_tsd_set() is called within example_tsd_cleanup(), it will be
52234370Sjasone * called again.  This is similar to how pthreads TSD destruction works, except
53234370Sjasone * that pthreads only calls the cleanup function again if the value was set to
54234370Sjasone * non-NULL.
55234370Sjasone */
56234370Sjasone
57234370Sjasone/* malloc_tsd_protos(). */
58234370Sjasone#define	malloc_tsd_protos(a_attr, a_name, a_type)			\
59234370Sjasonea_attr bool								\
60234370Sjasonea_name##_tsd_boot(void);						\
61234370Sjasonea_attr a_type *								\
62234370Sjasonea_name##_tsd_get(void);							\
63234370Sjasonea_attr void								\
64234370Sjasonea_name##_tsd_set(a_type *val);
65234370Sjasone
66234370Sjasone/* malloc_tsd_externs(). */
67234370Sjasone#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
68234370Sjasone#define	malloc_tsd_externs(a_name, a_type)				\
69234370Sjasoneextern __thread a_type	a_name##_tls;					\
70234370Sjasoneextern __thread bool	a_name##_initialized;				\
71234370Sjasoneextern bool		a_name##_booted;
72234370Sjasone#elif (defined(JEMALLOC_TLS))
73234370Sjasone#define	malloc_tsd_externs(a_name, a_type)				\
74234370Sjasoneextern __thread a_type	a_name##_tls;					\
75234370Sjasoneextern pthread_key_t	a_name##_tsd;					\
76234370Sjasoneextern bool		a_name##_booted;
77235238Sjasone#elif (defined(_WIN32))
78235238Sjasone#define malloc_tsd_externs(a_name, a_type)				\
79235238Sjasoneextern DWORD		a_name##_tsd;					\
80235238Sjasoneextern bool		a_name##_booted;
81234370Sjasone#else
82234370Sjasone#define	malloc_tsd_externs(a_name, a_type)				\
83234370Sjasoneextern pthread_key_t	a_name##_tsd;					\
84234370Sjasoneextern bool		a_name##_booted;
85234370Sjasone#endif
86234370Sjasone
87234370Sjasone/* malloc_tsd_data(). */
88234370Sjasone#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
89234370Sjasone#define	malloc_tsd_data(a_attr, a_name, a_type, a_initializer)		\
90234370Sjasonea_attr __thread a_type JEMALLOC_TLS_MODEL				\
91234370Sjasone    a_name##_tls = a_initializer;					\
92234370Sjasonea_attr __thread bool JEMALLOC_TLS_MODEL					\
93234370Sjasone    a_name##_initialized = false;					\
94234370Sjasonea_attr bool		a_name##_booted = false;
95234370Sjasone#elif (defined(JEMALLOC_TLS))
96234370Sjasone#define	malloc_tsd_data(a_attr, a_name, a_type, a_initializer)		\
97234370Sjasonea_attr __thread a_type JEMALLOC_TLS_MODEL				\
98234370Sjasone    a_name##_tls = a_initializer;					\
99234370Sjasonea_attr pthread_key_t	a_name##_tsd;					\
100234370Sjasonea_attr bool		a_name##_booted = false;
101235238Sjasone#elif (defined(_WIN32))
102235238Sjasone#define	malloc_tsd_data(a_attr, a_name, a_type, a_initializer)		\
103235238Sjasonea_attr DWORD		a_name##_tsd;					\
104235238Sjasonea_attr bool		a_name##_booted = false;
105234370Sjasone#else
106234370Sjasone#define	malloc_tsd_data(a_attr, a_name, a_type, a_initializer)		\
107234370Sjasonea_attr pthread_key_t	a_name##_tsd;					\
108234370Sjasonea_attr bool		a_name##_booted = false;
109234370Sjasone#endif
110234370Sjasone
111234370Sjasone/* malloc_tsd_funcs(). */
112234370Sjasone#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
113234370Sjasone#define	malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,		\
114234370Sjasone    a_cleanup)								\
115234370Sjasone/* Initialization/cleanup. */						\
116234370Sjasonea_attr bool								\
117234543Sjasonea_name##_tsd_cleanup_wrapper(void)					\
118234370Sjasone{									\
119234370Sjasone									\
120234370Sjasone	if (a_name##_initialized) {					\
121234370Sjasone		a_name##_initialized = false;				\
122234569Sjasone		a_cleanup(&a_name##_tls);				\
123234370Sjasone	}								\
124234370Sjasone	return (a_name##_initialized);					\
125234370Sjasone}									\
126234370Sjasonea_attr bool								\
127234370Sjasonea_name##_tsd_boot(void)							\
128234370Sjasone{									\
129234370Sjasone									\
130234370Sjasone	if (a_cleanup != malloc_tsd_no_cleanup) {			\
131234370Sjasone		malloc_tsd_cleanup_register(				\
132234543Sjasone		    &a_name##_tsd_cleanup_wrapper);			\
133234370Sjasone	}								\
134234370Sjasone	a_name##_booted = true;						\
135234370Sjasone	return (false);							\
136234370Sjasone}									\
137234370Sjasone/* Get/set. */								\
138234370Sjasonea_attr a_type *								\
139234370Sjasonea_name##_tsd_get(void)							\
140234370Sjasone{									\
141234370Sjasone									\
142234370Sjasone	assert(a_name##_booted);					\
143234370Sjasone	return (&a_name##_tls);						\
144234370Sjasone}									\
145234370Sjasonea_attr void								\
146234370Sjasonea_name##_tsd_set(a_type *val)						\
147234370Sjasone{									\
148234370Sjasone									\
149234370Sjasone	assert(a_name##_booted);					\
150234370Sjasone	a_name##_tls = (*val);						\
151234370Sjasone	if (a_cleanup != malloc_tsd_no_cleanup)				\
152234370Sjasone		a_name##_initialized = true;				\
153234370Sjasone}
154234370Sjasone#elif (defined(JEMALLOC_TLS))
155234370Sjasone#define	malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,		\
156234370Sjasone    a_cleanup)								\
157234370Sjasone/* Initialization/cleanup. */						\
158234370Sjasonea_attr bool								\
159234370Sjasonea_name##_tsd_boot(void)							\
160234370Sjasone{									\
161234370Sjasone									\
162234370Sjasone	if (a_cleanup != malloc_tsd_no_cleanup) {			\
163234370Sjasone		if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0)	\
164234370Sjasone			return (true);					\
165234370Sjasone	}								\
166234370Sjasone	a_name##_booted = true;						\
167234370Sjasone	return (false);							\
168234370Sjasone}									\
169234370Sjasone/* Get/set. */								\
170234370Sjasonea_attr a_type *								\
171234370Sjasonea_name##_tsd_get(void)							\
172234370Sjasone{									\
173234370Sjasone									\
174234370Sjasone	assert(a_name##_booted);					\
175234370Sjasone	return (&a_name##_tls);						\
176234370Sjasone}									\
177234370Sjasonea_attr void								\
178234370Sjasonea_name##_tsd_set(a_type *val)						\
179234370Sjasone{									\
180234370Sjasone									\
181234370Sjasone	assert(a_name##_booted);					\
182234370Sjasone	a_name##_tls = (*val);						\
183234370Sjasone	if (a_cleanup != malloc_tsd_no_cleanup) {			\
184234370Sjasone		if (pthread_setspecific(a_name##_tsd,			\
185234370Sjasone		    (void *)(&a_name##_tls))) {				\
186234370Sjasone			malloc_write("<jemalloc>: Error"		\
187234370Sjasone			    " setting TSD for "#a_name"\n");		\
188234370Sjasone			if (opt_abort)					\
189234370Sjasone				abort();				\
190234370Sjasone		}							\
191234370Sjasone	}								\
192234370Sjasone}
193235238Sjasone#elif (defined(_WIN32))
194235238Sjasone#define	malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,		\
195235238Sjasone    a_cleanup)								\
196235238Sjasone/* Data structure. */							\
197235238Sjasonetypedef struct {							\
198235238Sjasone	bool	initialized;						\
199235238Sjasone	a_type	val;							\
200235238Sjasone} a_name##_tsd_wrapper_t;						\
201235238Sjasone/* Initialization/cleanup. */						\
202235238Sjasonea_attr bool								\
203235238Sjasonea_name##_tsd_cleanup_wrapper(void)					\
204235238Sjasone{									\
205235238Sjasone	a_name##_tsd_wrapper_t *wrapper;				\
206235238Sjasone									\
207235238Sjasone	wrapper = (a_name##_tsd_wrapper_t *) TlsGetValue(a_name##_tsd);	\
208235238Sjasone	if (wrapper == NULL)						\
209235238Sjasone		return (false);						\
210235238Sjasone	if (a_cleanup != malloc_tsd_no_cleanup &&			\
211235238Sjasone	    wrapper->initialized) {					\
212235238Sjasone		a_type val = wrapper->val;				\
213235238Sjasone		a_type tsd_static_data = a_initializer;			\
214235238Sjasone		wrapper->initialized = false;				\
215235238Sjasone		wrapper->val = tsd_static_data;				\
216235238Sjasone		a_cleanup(&val);					\
217235238Sjasone		if (wrapper->initialized) {				\
218235238Sjasone			/* Trigger another cleanup round. */		\
219235238Sjasone			return (true);					\
220235238Sjasone		}							\
221235238Sjasone	}								\
222235238Sjasone	malloc_tsd_dalloc(wrapper);					\
223235238Sjasone	return (false);							\
224235238Sjasone}									\
225235238Sjasonea_attr bool								\
226235238Sjasonea_name##_tsd_boot(void)							\
227235238Sjasone{									\
228235238Sjasone									\
229235238Sjasone	a_name##_tsd = TlsAlloc();					\
230235238Sjasone	if (a_name##_tsd == TLS_OUT_OF_INDEXES)				\
231235238Sjasone		return (true);						\
232235238Sjasone	if (a_cleanup != malloc_tsd_no_cleanup) {			\
233235238Sjasone		malloc_tsd_cleanup_register(				\
234235238Sjasone		    &a_name##_tsd_cleanup_wrapper);			\
235235238Sjasone	}								\
236235238Sjasone	a_name##_booted = true;						\
237235238Sjasone	return (false);							\
238235238Sjasone}									\
239235238Sjasone/* Get/set. */								\
240235238Sjasonea_attr a_name##_tsd_wrapper_t *						\
241235238Sjasonea_name##_tsd_get_wrapper(void)						\
242235238Sjasone{									\
243235238Sjasone	a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)	\
244235238Sjasone	    TlsGetValue(a_name##_tsd);					\
245235238Sjasone									\
246235238Sjasone	if (wrapper == NULL) {						\
247235238Sjasone		wrapper = (a_name##_tsd_wrapper_t *)			\
248235238Sjasone		    malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t));	\
249235238Sjasone		if (wrapper == NULL) {					\
250235238Sjasone			malloc_write("<jemalloc>: Error allocating"	\
251235238Sjasone			    " TSD for "#a_name"\n");			\
252235238Sjasone			abort();					\
253235238Sjasone		} else {						\
254235238Sjasone			static a_type tsd_static_data = a_initializer;	\
255235238Sjasone			wrapper->initialized = false;			\
256235238Sjasone			wrapper->val = tsd_static_data;			\
257235238Sjasone		}							\
258235238Sjasone		if (!TlsSetValue(a_name##_tsd, (void *)wrapper)) {	\
259235238Sjasone			malloc_write("<jemalloc>: Error setting"	\
260235238Sjasone			    " TSD for "#a_name"\n");			\
261235238Sjasone			abort();					\
262235238Sjasone		}							\
263235238Sjasone	}								\
264235238Sjasone	return (wrapper);						\
265235238Sjasone}									\
266235238Sjasonea_attr a_type *								\
267235238Sjasonea_name##_tsd_get(void)							\
268235238Sjasone{									\
269235238Sjasone	a_name##_tsd_wrapper_t *wrapper;				\
270235238Sjasone									\
271235238Sjasone	assert(a_name##_booted);					\
272235238Sjasone	wrapper = a_name##_tsd_get_wrapper();				\
273235238Sjasone	return (&wrapper->val);						\
274235238Sjasone}									\
275235238Sjasonea_attr void								\
276235238Sjasonea_name##_tsd_set(a_type *val)						\
277235238Sjasone{									\
278235238Sjasone	a_name##_tsd_wrapper_t *wrapper;				\
279235238Sjasone									\
280235238Sjasone	assert(a_name##_booted);					\
281235238Sjasone	wrapper = a_name##_tsd_get_wrapper();				\
282235238Sjasone	wrapper->val = *(val);						\
283235238Sjasone	if (a_cleanup != malloc_tsd_no_cleanup)				\
284235238Sjasone		wrapper->initialized = true;				\
285235238Sjasone}
286234370Sjasone#else
287234370Sjasone#define	malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,		\
288234370Sjasone    a_cleanup)								\
289234370Sjasone/* Data structure. */							\
290234370Sjasonetypedef struct {							\
291234370Sjasone	bool	initialized;						\
292234370Sjasone	a_type	val;							\
293234370Sjasone} a_name##_tsd_wrapper_t;						\
294234370Sjasone/* Initialization/cleanup. */						\
295234370Sjasonea_attr void								\
296234370Sjasonea_name##_tsd_cleanup_wrapper(void *arg)					\
297234370Sjasone{									\
298234370Sjasone	a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\
299234370Sjasone									\
300234370Sjasone	if (a_cleanup != malloc_tsd_no_cleanup &&			\
301234370Sjasone	    wrapper->initialized) {					\
302234370Sjasone		wrapper->initialized = false;				\
303234370Sjasone		a_cleanup(&wrapper->val);				\
304234370Sjasone		if (wrapper->initialized) {				\
305234370Sjasone			/* Trigger another cleanup round. */		\
306234370Sjasone			if (pthread_setspecific(a_name##_tsd,		\
307234370Sjasone			    (void *)wrapper)) {				\
308234370Sjasone				malloc_write("<jemalloc>: Error"	\
309234370Sjasone				    " setting TSD for "#a_name"\n");	\
310234370Sjasone				if (opt_abort)				\
311234370Sjasone					abort();			\
312234370Sjasone			}						\
313234370Sjasone			return;						\
314234370Sjasone		}							\
315234370Sjasone	}								\
316234543Sjasone	malloc_tsd_dalloc(wrapper);					\
317234370Sjasone}									\
318234370Sjasonea_attr bool								\
319234370Sjasonea_name##_tsd_boot(void)							\
320234370Sjasone{									\
321234370Sjasone									\
322234370Sjasone	if (pthread_key_create(&a_name##_tsd,				\
323234370Sjasone	    a_name##_tsd_cleanup_wrapper) != 0)				\
324234370Sjasone		return (true);						\
325234370Sjasone	a_name##_booted = true;						\
326234370Sjasone	return (false);							\
327234370Sjasone}									\
328234370Sjasone/* Get/set. */								\
329234370Sjasonea_attr a_name##_tsd_wrapper_t *						\
330234370Sjasonea_name##_tsd_get_wrapper(void)						\
331234370Sjasone{									\
332234370Sjasone	a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)	\
333234370Sjasone	    pthread_getspecific(a_name##_tsd);				\
334234370Sjasone									\
335234370Sjasone	if (wrapper == NULL) {						\
336234370Sjasone		wrapper = (a_name##_tsd_wrapper_t *)			\
337234370Sjasone		    malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t));	\
338234370Sjasone		if (wrapper == NULL) {					\
339234370Sjasone			malloc_write("<jemalloc>: Error allocating"	\
340234370Sjasone			    " TSD for "#a_name"\n");			\
341234543Sjasone			abort();					\
342234370Sjasone		} else {						\
343234370Sjasone			static a_type tsd_static_data = a_initializer;	\
344234543Sjasone			wrapper->initialized = false;			\
345234370Sjasone			wrapper->val = tsd_static_data;			\
346234370Sjasone		}							\
347234370Sjasone		if (pthread_setspecific(a_name##_tsd,			\
348234370Sjasone		    (void *)wrapper)) {					\
349234370Sjasone			malloc_write("<jemalloc>: Error setting"	\
350234370Sjasone			    " TSD for "#a_name"\n");			\
351234543Sjasone			abort();					\
352234370Sjasone		}							\
353234370Sjasone	}								\
354234370Sjasone	return (wrapper);						\
355234370Sjasone}									\
356234370Sjasonea_attr a_type *								\
357234370Sjasonea_name##_tsd_get(void)							\
358234370Sjasone{									\
359234370Sjasone	a_name##_tsd_wrapper_t *wrapper;				\
360234370Sjasone									\
361234370Sjasone	assert(a_name##_booted);					\
362234370Sjasone	wrapper = a_name##_tsd_get_wrapper();				\
363234370Sjasone	return (&wrapper->val);						\
364234370Sjasone}									\
365234370Sjasonea_attr void								\
366234370Sjasonea_name##_tsd_set(a_type *val)						\
367234370Sjasone{									\
368234370Sjasone	a_name##_tsd_wrapper_t *wrapper;				\
369234370Sjasone									\
370234370Sjasone	assert(a_name##_booted);					\
371234370Sjasone	wrapper = a_name##_tsd_get_wrapper();				\
372234370Sjasone	wrapper->val = *(val);						\
373234370Sjasone	if (a_cleanup != malloc_tsd_no_cleanup)				\
374234370Sjasone		wrapper->initialized = true;				\
375234370Sjasone}
376234370Sjasone#endif
377234370Sjasone
378234370Sjasone#endif /* JEMALLOC_H_TYPES */
379234370Sjasone/******************************************************************************/
380234370Sjasone#ifdef JEMALLOC_H_STRUCTS
381234370Sjasone
382234370Sjasone#endif /* JEMALLOC_H_STRUCTS */
383234370Sjasone/******************************************************************************/
384234370Sjasone#ifdef JEMALLOC_H_EXTERNS
385234370Sjasone
386234370Sjasonevoid	*malloc_tsd_malloc(size_t size);
387234370Sjasonevoid	malloc_tsd_dalloc(void *wrapper);
388234370Sjasonevoid	malloc_tsd_no_cleanup(void *);
389234543Sjasonevoid	malloc_tsd_cleanup_register(bool (*f)(void));
390234370Sjasonevoid	malloc_tsd_boot(void);
391234370Sjasone
392234370Sjasone#endif /* JEMALLOC_H_EXTERNS */
393234370Sjasone/******************************************************************************/
394234370Sjasone#ifdef JEMALLOC_H_INLINES
395234370Sjasone
396234370Sjasone#endif /* JEMALLOC_H_INLINES */
397234370Sjasone/******************************************************************************/
398