]> git.saurik.com Git - redis.git/blame - deps/jemalloc.orig/include/jemalloc/internal/rtree.h
Jemalloc updated to 3.0.0.
[redis.git] / deps / jemalloc.orig / include / jemalloc / internal / rtree.h
CommitLineData
4934f93d 1/*
2 * This radix tree implementation is tailored to the singular purpose of
3 * tracking which chunks are currently owned by jemalloc. This functionality
4 * is mandatory for OS X, where jemalloc must be able to respond to object
5 * ownership queries.
6 *
7 *******************************************************************************
8 */
9#ifdef JEMALLOC_H_TYPES
10
11typedef struct rtree_s rtree_t;
12
13/*
14 * Size of each radix tree node (must be a power of 2). This impacts tree
15 * depth.
16 */
17#if (LG_SIZEOF_PTR == 2)
18# define RTREE_NODESIZE (1U << 14)
19#else
20# define RTREE_NODESIZE CACHELINE
21#endif
22
23#endif /* JEMALLOC_H_TYPES */
24/******************************************************************************/
25#ifdef JEMALLOC_H_STRUCTS
26
27struct rtree_s {
28 malloc_mutex_t mutex;
29 void **root;
30 unsigned height;
31 unsigned level2bits[1]; /* Dynamically sized. */
32};
33
34#endif /* JEMALLOC_H_STRUCTS */
35/******************************************************************************/
36#ifdef JEMALLOC_H_EXTERNS
37
38rtree_t *rtree_new(unsigned bits);
39
40#endif /* JEMALLOC_H_EXTERNS */
41/******************************************************************************/
42#ifdef JEMALLOC_H_INLINES
43
44#ifndef JEMALLOC_ENABLE_INLINE
45#ifndef JEMALLOC_DEBUG
46void *rtree_get_locked(rtree_t *rtree, uintptr_t key);
47#endif
48void *rtree_get(rtree_t *rtree, uintptr_t key);
49bool rtree_set(rtree_t *rtree, uintptr_t key, void *val);
50#endif
51
52#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_))
53#define RTREE_GET_GENERATE(f) \
54/* The least significant bits of the key are ignored. */ \
55JEMALLOC_INLINE void * \
56f(rtree_t *rtree, uintptr_t key) \
57{ \
58 void *ret; \
59 uintptr_t subkey; \
60 unsigned i, lshift, height, bits; \
61 void **node, **child; \
62 \
63 RTREE_LOCK(&rtree->mutex); \
64 for (i = lshift = 0, height = rtree->height, node = rtree->root;\
65 i < height - 1; \
66 i++, lshift += bits, node = child) { \
67 bits = rtree->level2bits[i]; \
68 subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR + \
69 3)) - bits); \
70 child = (void**)node[subkey]; \
71 if (child == NULL) { \
72 RTREE_UNLOCK(&rtree->mutex); \
73 return (NULL); \
74 } \
75 } \
76 \
77 /* \
78 * node is a leaf, so it contains values rather than node \
79 * pointers. \
80 */ \
81 bits = rtree->level2bits[i]; \
82 subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR+3)) - \
83 bits); \
84 ret = node[subkey]; \
85 RTREE_UNLOCK(&rtree->mutex); \
86 \
87 RTREE_GET_VALIDATE \
88 return (ret); \
89}
90
91#ifdef JEMALLOC_DEBUG
92# define RTREE_LOCK(l) malloc_mutex_lock(l)
93# define RTREE_UNLOCK(l) malloc_mutex_unlock(l)
94# define RTREE_GET_VALIDATE
95RTREE_GET_GENERATE(rtree_get_locked)
96# undef RTREE_LOCK
97# undef RTREE_UNLOCK
98# undef RTREE_GET_VALIDATE
99#endif
100
101#define RTREE_LOCK(l)
102#define RTREE_UNLOCK(l)
103#ifdef JEMALLOC_DEBUG
104 /*
105 * Suppose that it were possible for a jemalloc-allocated chunk to be
106 * munmap()ped, followed by a different allocator in another thread re-using
107 * overlapping virtual memory, all without invalidating the cached rtree
108 * value. The result would be a false positive (the rtree would claim that
109 * jemalloc owns memory that it had actually discarded). This scenario
110 * seems impossible, but the following assertion is a prudent sanity check.
111 */
112# define RTREE_GET_VALIDATE \
113 assert(rtree_get_locked(rtree, key) == ret);
114#else
115# define RTREE_GET_VALIDATE
116#endif
117RTREE_GET_GENERATE(rtree_get)
118#undef RTREE_LOCK
119#undef RTREE_UNLOCK
120#undef RTREE_GET_VALIDATE
121
122JEMALLOC_INLINE bool
123rtree_set(rtree_t *rtree, uintptr_t key, void *val)
124{
125 uintptr_t subkey;
126 unsigned i, lshift, height, bits;
127 void **node, **child;
128
129 malloc_mutex_lock(&rtree->mutex);
130 for (i = lshift = 0, height = rtree->height, node = rtree->root;
131 i < height - 1;
132 i++, lshift += bits, node = child) {
133 bits = rtree->level2bits[i];
134 subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR+3)) -
135 bits);
136 child = (void**)node[subkey];
137 if (child == NULL) {
138 child = (void**)base_alloc(sizeof(void *) <<
139 rtree->level2bits[i+1]);
140 if (child == NULL) {
141 malloc_mutex_unlock(&rtree->mutex);
142 return (true);
143 }
144 memset(child, 0, sizeof(void *) <<
145 rtree->level2bits[i+1]);
146 node[subkey] = child;
147 }
148 }
149
150 /* node is a leaf, so it contains values rather than node pointers. */
151 bits = rtree->level2bits[i];
152 subkey = (key << lshift) >> ((ZU(1) << (LG_SIZEOF_PTR+3)) - bits);
153 node[subkey] = val;
154 malloc_mutex_unlock(&rtree->mutex);
155
156 return (false);
157}
158#endif
159
160#endif /* JEMALLOC_H_INLINES */
161/******************************************************************************/