tsd.h revision a19e87fbad020e8dd3d26682032929e8e5ae71c1
11c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/******************************************************************************/
21c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#ifdef JEMALLOC_H_TYPES
31c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
41c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* Maximum number of malloc_tsd users with cleanup functions. */
51c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	MALLOC_TSD_CLEANUPS_MAX	8
61c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
71c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáktypedef bool (*malloc_tsd_cleanup_t)(void);
81c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
91c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/*
101c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * TLS/TSD-agnostic macro-based implementation of thread-specific data.  There
111c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * are four macros that support (at least) three use cases: file-private,
121c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * library-private, and library-private inlined.  Following is an example
131c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * library-private tsd variable:
141c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
151c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * In example.h:
161c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   typedef struct {
171c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *           int x;
181c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *           int y;
191c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   } example_t;
201c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0})
211c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   malloc_tsd_protos(, example, example_t *)
221c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   malloc_tsd_externs(example, example_t *)
231c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * In example.c:
241c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   malloc_tsd_data(, example, example_t *, EX_INITIALIZER)
251c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   malloc_tsd_funcs(, example, example_t *, EX_INITIALIZER,
261c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *       example_tsd_cleanup)
271c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
281c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * The result is a set of generated functions, e.g.:
291c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
301c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   bool example_tsd_boot(void) {...}
311c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   example_t **example_tsd_get() {...}
321c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   void example_tsd_set(example_t **val) {...}
331c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
341c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * Note that all of the functions deal in terms of (a_type *) rather than
351c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * (a_type)  so that it is possible to support non-pointer types (unlike
361c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * pthreads TSD).  example_tsd_cleanup() is passed an (a_type *) pointer that is
371c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * cast to (void *).  This means that the cleanup function needs to cast *and*
381c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * dereference the function argument, e.g.:
391c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
401c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   void
411c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   example_tsd_cleanup(void *arg)
421c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   {
431c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *           example_t *example = *(example_t **)arg;
441c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
451c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *           [...]
461c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *           if ([want the cleanup function to be called again]) {
471c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *                   example_tsd_set(&example);
481c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *           }
491c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *   }
501c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
511c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * If example_tsd_set() is called within example_tsd_cleanup(), it will be
521c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * called again.  This is similar to how pthreads TSD destruction works, except
531c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * that pthreads only calls the cleanup function again if the value was set to
541c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * non-NULL.
551c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák */
561c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
571c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* malloc_tsd_protos(). */
581c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	malloc_tsd_protos(a_attr, a_name, a_type)			\
591c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool								\
601c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_boot(void);						\
611c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr a_type *								\
621c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_get(void);							\
631c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr void								\
641c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_set(a_type *val);
651c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
661c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* malloc_tsd_externs(). */
671c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
681c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	malloc_tsd_externs(a_name, a_type)				\
691c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern __thread a_type	a_name##_tls;					\
701c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern __thread bool	a_name##_initialized;				\
711c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern bool		a_name##_booted;
721c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#elif (defined(JEMALLOC_TLS))
731c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	malloc_tsd_externs(a_name, a_type)				\
741c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern __thread a_type	a_name##_tls;					\
751c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern pthread_key_t	a_name##_tsd;					\
761c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern bool		a_name##_booted;
771c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#elif (defined(_WIN32))
781c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define malloc_tsd_externs(a_name, a_type)				\
791c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern DWORD		a_name##_tsd;					\
801c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern bool		a_name##_booted;
811c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#else
821c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	malloc_tsd_externs(a_name, a_type)				\
831c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern pthread_key_t	a_name##_tsd;					\
841c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákextern bool		a_name##_booted;
851c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#endif
861c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
871c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* malloc_tsd_data(). */
881c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
891c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	malloc_tsd_data(a_attr, a_name, a_type, a_initializer)		\
901c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr __thread a_type JEMALLOC_TLS_MODEL				\
911c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák    a_name##_tls = a_initializer;					\
921c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr __thread bool JEMALLOC_TLS_MODEL					\
931c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák    a_name##_initialized = false;					\
941c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool		a_name##_booted = false;
951c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#elif (defined(JEMALLOC_TLS))
961c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	malloc_tsd_data(a_attr, a_name, a_type, a_initializer)		\
971c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr __thread a_type JEMALLOC_TLS_MODEL				\
981c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák    a_name##_tls = a_initializer;					\
991c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr pthread_key_t	a_name##_tsd;					\
1001c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool		a_name##_booted = false;
1011c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#elif (defined(_WIN32))
1021c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	malloc_tsd_data(a_attr, a_name, a_type, a_initializer)		\
1031c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr DWORD		a_name##_tsd;					\
1041c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool		a_name##_booted = false;
1051c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#else
1061c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	malloc_tsd_data(a_attr, a_name, a_type, a_initializer)		\
1071c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr pthread_key_t	a_name##_tsd;					\
1081c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool		a_name##_booted = false;
1091c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#endif
1101c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1111c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* malloc_tsd_funcs(). */
1121c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
1131c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define	malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,		\
1141c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák    a_cleanup)								\
1151c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* Initialization/cleanup. */						\
1161c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool								\
1171c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_cleanup_wrapper(void)					\
1181c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{									\
1191c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák									\
1201c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (a_name##_initialized) {					\
1211c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		a_name##_initialized = false;				\
1221c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		a_cleanup(&a_name##_tls);				\
1231c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}								\
1241c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	return (a_name##_initialized);					\
1251c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}									\
1261c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr bool								\
1271c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_boot(void)							\
1281c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{									\
1291c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák									\
1301c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (a_cleanup != malloc_tsd_no_cleanup) {			\
1311c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		malloc_tsd_cleanup_register(				\
1321c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		    &a_name##_tsd_cleanup_wrapper);			\
1331c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}								\
1341c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	a_name##_booted = true;						\
1351c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	return (false);							\
1361c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}									\
1371c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/* Get/set. */								\
1381c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr a_type *								\
1391c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_get(void)							\
1401c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{									\
1411c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák									\
1421c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	assert(a_name##_booted);					\
1431c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	return (&a_name##_tls);						\
1441c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}									\
1451c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_attr void								\
1461c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšáka_name##_tsd_set(a_type *val)						\
1471c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{									\
1481c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák									\
1491c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	assert(a_name##_booted);					\
1501c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	a_name##_tls = (*val);						\
151	if (a_cleanup != malloc_tsd_no_cleanup)				\
152		a_name##_initialized = true;				\
153}
154#elif (defined(JEMALLOC_TLS))
155#define	malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,		\
156    a_cleanup)								\
157/* Initialization/cleanup. */						\
158a_attr bool								\
159a_name##_tsd_boot(void)							\
160{									\
161									\
162	if (a_cleanup != malloc_tsd_no_cleanup) {			\
163		if (pthread_key_create(&a_name##_tsd, a_cleanup) != 0)	\
164			return (true);					\
165	}								\
166	a_name##_booted = true;						\
167	return (false);							\
168}									\
169/* Get/set. */								\
170a_attr a_type *								\
171a_name##_tsd_get(void)							\
172{									\
173									\
174	assert(a_name##_booted);					\
175	return (&a_name##_tls);						\
176}									\
177a_attr void								\
178a_name##_tsd_set(a_type *val)						\
179{									\
180									\
181	assert(a_name##_booted);					\
182	a_name##_tls = (*val);						\
183	if (a_cleanup != malloc_tsd_no_cleanup) {			\
184		if (pthread_setspecific(a_name##_tsd,			\
185		    (void *)(&a_name##_tls))) {				\
186			malloc_write("<jemalloc>: Error"		\
187			    " setting TSD for "#a_name"\n");		\
188			if (opt_abort)					\
189				abort();				\
190		}							\
191	}								\
192}
193#elif (defined(_WIN32))
194#define	malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,		\
195    a_cleanup)								\
196/* Data structure. */							\
197typedef struct {							\
198	bool	initialized;						\
199	a_type	val;							\
200} a_name##_tsd_wrapper_t;						\
201/* Initialization/cleanup. */						\
202a_attr bool								\
203a_name##_tsd_cleanup_wrapper(void)					\
204{									\
205	a_name##_tsd_wrapper_t *wrapper;				\
206									\
207	wrapper = (a_name##_tsd_wrapper_t *) TlsGetValue(a_name##_tsd);	\
208	if (wrapper == NULL)						\
209		return (false);						\
210	if (a_cleanup != malloc_tsd_no_cleanup &&			\
211	    wrapper->initialized) {					\
212		a_type val = wrapper->val;				\
213		a_type tsd_static_data = a_initializer;			\
214		wrapper->initialized = false;				\
215		wrapper->val = tsd_static_data;				\
216		a_cleanup(&val);					\
217		if (wrapper->initialized) {				\
218			/* Trigger another cleanup round. */		\
219			return (true);					\
220		}							\
221	}								\
222	malloc_tsd_dalloc(wrapper);					\
223	return (false);							\
224}									\
225a_attr bool								\
226a_name##_tsd_boot(void)							\
227{									\
228									\
229	a_name##_tsd = TlsAlloc();					\
230	if (a_name##_tsd == TLS_OUT_OF_INDEXES)				\
231		return (true);						\
232	if (a_cleanup != malloc_tsd_no_cleanup) {			\
233		malloc_tsd_cleanup_register(				\
234		    &a_name##_tsd_cleanup_wrapper);			\
235	}								\
236	a_name##_booted = true;						\
237	return (false);							\
238}									\
239/* Get/set. */								\
240a_attr a_name##_tsd_wrapper_t *						\
241a_name##_tsd_get_wrapper(void)						\
242{									\
243	a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)	\
244	    TlsGetValue(a_name##_tsd);					\
245									\
246	if (wrapper == NULL) {						\
247		wrapper = (a_name##_tsd_wrapper_t *)			\
248		    malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t));	\
249		if (wrapper == NULL) {					\
250			malloc_write("<jemalloc>: Error allocating"	\
251			    " TSD for "#a_name"\n");			\
252			abort();					\
253		} else {						\
254			static a_type tsd_static_data = a_initializer;	\
255			wrapper->initialized = false;			\
256			wrapper->val = tsd_static_data;			\
257		}							\
258		if (!TlsSetValue(a_name##_tsd, (void *)wrapper)) {	\
259			malloc_write("<jemalloc>: Error setting"	\
260			    " TSD for "#a_name"\n");			\
261			abort();					\
262		}							\
263	}								\
264	return (wrapper);						\
265}									\
266a_attr a_type *								\
267a_name##_tsd_get(void)							\
268{									\
269	a_name##_tsd_wrapper_t *wrapper;				\
270									\
271	assert(a_name##_booted);					\
272	wrapper = a_name##_tsd_get_wrapper();				\
273	return (&wrapper->val);						\
274}									\
275a_attr void								\
276a_name##_tsd_set(a_type *val)						\
277{									\
278	a_name##_tsd_wrapper_t *wrapper;				\
279									\
280	assert(a_name##_booted);					\
281	wrapper = a_name##_tsd_get_wrapper();				\
282	wrapper->val = *(val);						\
283	if (a_cleanup != malloc_tsd_no_cleanup)				\
284		wrapper->initialized = true;				\
285}
286#else
287#define	malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer,		\
288    a_cleanup)								\
289/* Data structure. */							\
290typedef struct {							\
291	bool	initialized;						\
292	a_type	val;							\
293} a_name##_tsd_wrapper_t;						\
294/* Initialization/cleanup. */						\
295a_attr void								\
296a_name##_tsd_cleanup_wrapper(void *arg)					\
297{									\
298	a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)arg;\
299									\
300	if (a_cleanup != malloc_tsd_no_cleanup &&			\
301	    wrapper->initialized) {					\
302		wrapper->initialized = false;				\
303		a_cleanup(&wrapper->val);				\
304		if (wrapper->initialized) {				\
305			/* Trigger another cleanup round. */		\
306			if (pthread_setspecific(a_name##_tsd,		\
307			    (void *)wrapper)) {				\
308				malloc_write("<jemalloc>: Error"	\
309				    " setting TSD for "#a_name"\n");	\
310				if (opt_abort)				\
311					abort();			\
312			}						\
313			return;						\
314		}							\
315	}								\
316	malloc_tsd_dalloc(wrapper);					\
317}									\
318a_attr bool								\
319a_name##_tsd_boot(void)							\
320{									\
321									\
322	if (pthread_key_create(&a_name##_tsd,				\
323	    a_name##_tsd_cleanup_wrapper) != 0)				\
324		return (true);						\
325	a_name##_booted = true;						\
326	return (false);							\
327}									\
328/* Get/set. */								\
329a_attr a_name##_tsd_wrapper_t *						\
330a_name##_tsd_get_wrapper(void)						\
331{									\
332	a_name##_tsd_wrapper_t *wrapper = (a_name##_tsd_wrapper_t *)	\
333	    pthread_getspecific(a_name##_tsd);				\
334									\
335	if (wrapper == NULL) {						\
336		wrapper = (a_name##_tsd_wrapper_t *)			\
337		    malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t));	\
338		if (wrapper == NULL) {					\
339			malloc_write("<jemalloc>: Error allocating"	\
340			    " TSD for "#a_name"\n");			\
341			abort();					\
342		} else {						\
343			static a_type tsd_static_data = a_initializer;	\
344			wrapper->initialized = false;			\
345			wrapper->val = tsd_static_data;			\
346		}							\
347		if (pthread_setspecific(a_name##_tsd,			\
348		    (void *)wrapper)) {					\
349			malloc_write("<jemalloc>: Error setting"	\
350			    " TSD for "#a_name"\n");			\
351			abort();					\
352		}							\
353	}								\
354	return (wrapper);						\
355}									\
356a_attr a_type *								\
357a_name##_tsd_get(void)							\
358{									\
359	a_name##_tsd_wrapper_t *wrapper;				\
360									\
361	assert(a_name##_booted);					\
362	wrapper = a_name##_tsd_get_wrapper();				\
363	return (&wrapper->val);						\
364}									\
365a_attr void								\
366a_name##_tsd_set(a_type *val)						\
367{									\
368	a_name##_tsd_wrapper_t *wrapper;				\
369									\
370	assert(a_name##_booted);					\
371	wrapper = a_name##_tsd_get_wrapper();				\
372	wrapper->val = *(val);						\
373	if (a_cleanup != malloc_tsd_no_cleanup)				\
374		wrapper->initialized = true;				\
375}
376#endif
377
378#endif /* JEMALLOC_H_TYPES */
379/******************************************************************************/
380#ifdef JEMALLOC_H_STRUCTS
381
382#endif /* JEMALLOC_H_STRUCTS */
383/******************************************************************************/
384#ifdef JEMALLOC_H_EXTERNS
385
386void	*malloc_tsd_malloc(size_t size);
387void	malloc_tsd_dalloc(void *wrapper);
388void	malloc_tsd_no_cleanup(void *);
389void	malloc_tsd_cleanup_register(bool (*f)(void));
390void	malloc_tsd_boot(void);
391
392#endif /* JEMALLOC_H_EXTERNS */
393/******************************************************************************/
394#ifdef JEMALLOC_H_INLINES
395
396#endif /* JEMALLOC_H_INLINES */
397/******************************************************************************/
398