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