12dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans/*
22dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans * This radix tree implementation is tailored to the singular purpose of
32dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans * tracking which chunks are currently owned by jemalloc.  This functionality
42dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans * is mandatory for OS X, where jemalloc must be able to respond to object
52dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans * ownership queries.
62dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans *
72dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans *******************************************************************************
82dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans */
92dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#ifdef JEMALLOC_H_TYPES
102dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
112dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evanstypedef struct rtree_s rtree_t;
122dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
132dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans/*
142dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans * Size of each radix tree node (must be a power of 2).  This impacts tree
152dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans * depth.
162dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans */
17b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans#define	RTREE_NODESIZE (1U << 16)
182dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
19b980cc774a9ccb208a82f4e9ccdcc695d06a960aJason Evanstypedef void *(rtree_alloc_t)(size_t);
20b980cc774a9ccb208a82f4e9ccdcc695d06a960aJason Evanstypedef void (rtree_dalloc_t)(void *);
21b980cc774a9ccb208a82f4e9ccdcc695d06a960aJason Evans
222dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#endif /* JEMALLOC_H_TYPES */
232dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans/******************************************************************************/
242dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#ifdef JEMALLOC_H_STRUCTS
252dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
262dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evansstruct rtree_s {
27b980cc774a9ccb208a82f4e9ccdcc695d06a960aJason Evans	rtree_alloc_t	*alloc;
28b980cc774a9ccb208a82f4e9ccdcc695d06a960aJason Evans	rtree_dalloc_t	*dalloc;
292dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	malloc_mutex_t	mutex;
302dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	void		**root;
312dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	unsigned	height;
322dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	unsigned	level2bits[1]; /* Dynamically sized. */
332dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans};
342dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
352dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#endif /* JEMALLOC_H_STRUCTS */
362dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans/******************************************************************************/
372dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#ifdef JEMALLOC_H_EXTERNS
382dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
39b980cc774a9ccb208a82f4e9ccdcc695d06a960aJason Evansrtree_t	*rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc);
40b980cc774a9ccb208a82f4e9ccdcc695d06a960aJason Evansvoid	rtree_delete(rtree_t *rtree);
4120f1fc95adb35ea63dc61f47f2b0ffbd37d39f32Jason Evansvoid	rtree_prefork(rtree_t *rtree);
4220f1fc95adb35ea63dc61f47f2b0ffbd37d39f32Jason Evansvoid	rtree_postfork_parent(rtree_t *rtree);
4320f1fc95adb35ea63dc61f47f2b0ffbd37d39f32Jason Evansvoid	rtree_postfork_child(rtree_t *rtree);
442dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
452dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#endif /* JEMALLOC_H_EXTERNS */
462dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans/******************************************************************************/
472dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#ifdef JEMALLOC_H_INLINES
482dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
492dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#ifndef JEMALLOC_ENABLE_INLINE
50b980cc774a9ccb208a82f4e9ccdcc695d06a960aJason Evans#ifdef JEMALLOC_DEBUG
51b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evansuint8_t rtree_get_locked(rtree_t *rtree, uintptr_t key);
522dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#endif
53b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evansuint8_t	rtree_get(rtree_t *rtree, uintptr_t key);
54b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evansbool	rtree_set(rtree_t *rtree, uintptr_t key, uint8_t val);
552dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#endif
562dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
570657f12acd43eb2082a71230341449eca648bc9bJason Evans#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_))
582dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#define	RTREE_GET_GENERATE(f)						\
592dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans/* The least significant bits of the key are ignored. */		\
60b954bc5d3a65966df0ce7801cd6102542b5e894bJason EvansJEMALLOC_INLINE uint8_t							\
612dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evansf(rtree_t *rtree, uintptr_t key)					\
622dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans{									\
63b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans	uint8_t ret;							\
642dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	uintptr_t subkey;						\
652dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	unsigned i, lshift, height, bits;				\
662dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	void **node, **child;						\
672dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans									\
682dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	RTREE_LOCK(&rtree->mutex);					\
692dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	for (i = lshift = 0, height = rtree->height, node = rtree->root;\
702dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	    i < height - 1;						\
712dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	    i++, lshift += bits, node = child) {			\
722dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		bits = rtree->level2bits[i];				\
73b980cc774a9ccb208a82f4e9ccdcc695d06a960aJason Evans		subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR +	\
742dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		    3)) - bits);					\
752dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		child = (void**)node[subkey];				\
762dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		if (child == NULL) {					\
772dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans			RTREE_UNLOCK(&rtree->mutex);			\
78b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans			return (0);					\
792dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		}							\
802dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	}								\
812dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans									\
822dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	/*								\
832dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	 * node is a leaf, so it contains values rather than node	\
842dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	 * pointers.							\
852dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	 */								\
862dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	bits = rtree->level2bits[i];					\
872dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR+3)) -	\
882dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	    bits);							\
89b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans	{								\
90b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans		uint8_t *leaf = (uint8_t *)node;			\
91b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans		ret = leaf[subkey];					\
92b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans	}								\
932dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	RTREE_UNLOCK(&rtree->mutex);					\
942dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans									\
952dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	RTREE_GET_VALIDATE						\
962dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	return (ret);							\
972dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans}
982dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
992dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#ifdef JEMALLOC_DEBUG
1002dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#  define RTREE_LOCK(l)		malloc_mutex_lock(l)
1012dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#  define RTREE_UNLOCK(l)	malloc_mutex_unlock(l)
1022dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#  define RTREE_GET_VALIDATE
1032dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason EvansRTREE_GET_GENERATE(rtree_get_locked)
1042dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#  undef RTREE_LOCK
1052dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#  undef RTREE_UNLOCK
1062dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#  undef RTREE_GET_VALIDATE
1072dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#endif
1082dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
1092dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#define	RTREE_LOCK(l)
1102dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#define	RTREE_UNLOCK(l)
1112dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#ifdef JEMALLOC_DEBUG
1122dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans   /*
1132dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans    * Suppose that it were possible for a jemalloc-allocated chunk to be
1142dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans    * munmap()ped, followed by a different allocator in another thread re-using
1152dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans    * overlapping virtual memory, all without invalidating the cached rtree
1162dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans    * value.  The result would be a false positive (the rtree would claim that
1172dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans    * jemalloc owns memory that it had actually discarded).  This scenario
1182dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans    * seems impossible, but the following assertion is a prudent sanity check.
1192dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans    */
1202dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#  define RTREE_GET_VALIDATE						\
1212dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	assert(rtree_get_locked(rtree, key) == ret);
1222dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#else
1232dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#  define RTREE_GET_VALIDATE
1242dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#endif
1252dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason EvansRTREE_GET_GENERATE(rtree_get)
1262dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#undef RTREE_LOCK
1272dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#undef RTREE_UNLOCK
1282dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#undef RTREE_GET_VALIDATE
1292dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
1302dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason EvansJEMALLOC_INLINE bool
131b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evansrtree_set(rtree_t *rtree, uintptr_t key, uint8_t val)
1322dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans{
1332dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	uintptr_t subkey;
1342dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	unsigned i, lshift, height, bits;
1352dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	void **node, **child;
1362dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
1372dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	malloc_mutex_lock(&rtree->mutex);
1382dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	for (i = lshift = 0, height = rtree->height, node = rtree->root;
1392dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	    i < height - 1;
1402dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	    i++, lshift += bits, node = child) {
1412dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		bits = rtree->level2bits[i];
1422dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR+3)) -
1432dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		    bits);
1442dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		child = (void**)node[subkey];
1452dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		if (child == NULL) {
146b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans			size_t size = ((i + 1 < height - 1) ? sizeof(void *)
147b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans			    : (sizeof(uint8_t))) << rtree->level2bits[i+1];
148b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans			child = (void**)rtree->alloc(size);
1492dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans			if (child == NULL) {
1502dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans				malloc_mutex_unlock(&rtree->mutex);
1512dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans				return (true);
1522dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans			}
153b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans			memset(child, 0, size);
1542dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans			node[subkey] = child;
1552dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans		}
1562dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	}
1572dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
1582dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	/* node is a leaf, so it contains values rather than node pointers. */
1592dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	bits = rtree->level2bits[i];
1602dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR+3)) - bits);
161b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans	{
162b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans		uint8_t *leaf = (uint8_t *)node;
163b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans		leaf[subkey] = val;
164b954bc5d3a65966df0ce7801cd6102542b5e894bJason Evans	}
1652dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	malloc_mutex_unlock(&rtree->mutex);
1662dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
1672dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans	return (false);
1682dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans}
1692dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#endif
1702dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans
1712dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans#endif /* JEMALLOC_H_INLINES */
1722dbecf1f6267fae7a161b9c39cfd4d04ce168a29Jason Evans/******************************************************************************/
173