Rizin
unix-like reverse engineering framework and cli tools
rtree.h
Go to the documentation of this file.
1 /*
2  * This radix tree implementation is tailored to the singular purpose of
3  * associating metadata with chunks that are currently owned by jemalloc.
4  *
5  *******************************************************************************
6  */
7 #ifdef JEMALLOC_H_TYPES
8 
9 typedef struct rtree_node_elm_s rtree_node_elm_t;
10 typedef struct rtree_level_s rtree_level_t;
11 typedef struct rtree_s rtree_t;
12 
13 /*
14  * RTREE_BITS_PER_LEVEL must be a power of two that is no larger than the
15  * machine address width.
16  */
17 #define LG_RTREE_BITS_PER_LEVEL 4
18 #define RTREE_BITS_PER_LEVEL (1U << LG_RTREE_BITS_PER_LEVEL)
19 /* Maximum rtree height. */
20 #define RTREE_HEIGHT_MAX \
21  ((1U << (LG_SIZEOF_PTR+3)) / RTREE_BITS_PER_LEVEL)
22 
23 /* Used for two-stage lock-free node initialization. */
24 #define RTREE_NODE_INITIALIZING ((rtree_node_elm_t *)0x1)
25 
26 /*
27  * The node allocation callback function's argument is the number of contiguous
28  * rtree_node_elm_t structures to allocate, and the resulting memory must be
29  * zeroed.
30  */
31 typedef rtree_node_elm_t *(rtree_node_alloc_t)(size_t);
32 typedef void (rtree_node_dalloc_t)(rtree_node_elm_t *);
33 
34 #endif /* JEMALLOC_H_TYPES */
35 /******************************************************************************/
36 #ifdef JEMALLOC_H_STRUCTS
37 
38 struct rtree_node_elm_s {
39  union {
40  void *pun;
41  rtree_node_elm_t *child;
42  extent_node_t *val;
43  };
44 };
45 
46 struct rtree_level_s {
47  /*
48  * A non-NULL subtree points to a subtree rooted along the hypothetical
49  * path to the leaf node corresponding to key 0. Depending on what keys
50  * have been used to store to the tree, an arbitrary combination of
51  * subtree pointers may remain NULL.
52  *
53  * Suppose keys comprise 48 bits, and LG_RTREE_BITS_PER_LEVEL is 4.
54  * This results in a 3-level tree, and the leftmost leaf can be directly
55  * accessed via subtrees[2], the subtree prefixed by 0x0000 (excluding
56  * 0x00000000) can be accessed via subtrees[1], and the remainder of the
57  * tree can be accessed via subtrees[0].
58  *
59  * levels[0] : [<unused> | 0x0001******** | 0x0002******** | ...]
60  *
61  * levels[1] : [<unused> | 0x00000001**** | 0x00000002**** | ... ]
62  *
63  * levels[2] : [val(0x000000000000) | val(0x000000000001) | ...]
64  *
65  * This has practical implications on x64, which currently uses only the
66  * lower 47 bits of virtual address space in userland, thus leaving
67  * subtrees[0] unused and avoiding a level of tree traversal.
68  */
69  union {
70  void *subtree_pun;
71  rtree_node_elm_t *subtree;
72  };
73  /* Number of key bits distinguished by this level. */
74  unsigned bits;
75  /*
76  * Cumulative number of key bits distinguished by traversing to
77  * corresponding tree level.
78  */
79  unsigned cumulative_bits;
80 };
81 
82 struct rtree_s {
83  rtree_node_alloc_t *alloc;
84  rtree_node_dalloc_t *dalloc;
85  unsigned height;
86  /*
87  * Precomputed table used to convert from the number of leading 0 key
88  * bits to which subtree level to start at.
89  */
90  unsigned start_level[RTREE_HEIGHT_MAX];
91  rtree_level_t levels[RTREE_HEIGHT_MAX];
92 };
93 
94 #endif /* JEMALLOC_H_STRUCTS */
95 /******************************************************************************/
96 #ifdef JEMALLOC_H_EXTERNS
97 
98 bool rtree_new(rtree_t *rtree, unsigned bits, rtree_node_alloc_t *alloc,
99  rtree_node_dalloc_t *dalloc);
100 void rtree_delete(rtree_t *rtree);
101 rtree_node_elm_t *rtree_subtree_read_hard(rtree_t *rtree,
102  unsigned level);
103 rtree_node_elm_t *rtree_child_read_hard(rtree_t *rtree,
104  rtree_node_elm_t *elm, unsigned level);
105 
106 #endif /* JEMALLOC_H_EXTERNS */
107 /******************************************************************************/
108 #ifdef JEMALLOC_H_INLINES
109 
110 #ifndef JEMALLOC_ENABLE_INLINE
111 unsigned rtree_start_level(rtree_t *rtree, uintptr_t key);
112 uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level);
113 
114 bool rtree_node_valid(rtree_node_elm_t *node);
115 rtree_node_elm_t *rtree_child_tryread(rtree_node_elm_t *elm,
116  bool dependent);
117 rtree_node_elm_t *rtree_child_read(rtree_t *rtree, rtree_node_elm_t *elm,
118  unsigned level, bool dependent);
119 extent_node_t *rtree_val_read(rtree_t *rtree, rtree_node_elm_t *elm,
120  bool dependent);
121 void rtree_val_write(rtree_t *rtree, rtree_node_elm_t *elm,
122  const extent_node_t *val);
123 rtree_node_elm_t *rtree_subtree_tryread(rtree_t *rtree, unsigned level,
124  bool dependent);
125 rtree_node_elm_t *rtree_subtree_read(rtree_t *rtree, unsigned level,
126  bool dependent);
127 
128 extent_node_t *rtree_get(rtree_t *rtree, uintptr_t key, bool dependent);
129 bool rtree_set(rtree_t *rtree, uintptr_t key, const extent_node_t *val);
130 #endif
131 
132 #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_))
133 JEMALLOC_ALWAYS_INLINE unsigned
134 rtree_start_level(rtree_t *rtree, uintptr_t key)
135 {
136  unsigned start_level;
137 
138  if (unlikely(key == 0))
139  return (rtree->height - 1);
140 
141  start_level = rtree->start_level[lg_floor(key) >>
142  LG_RTREE_BITS_PER_LEVEL];
143  assert(start_level < rtree->height);
144  return (start_level);
145 }
146 
148 rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level)
149 {
150 
151  return ((key >> ((ZU(1) << (LG_SIZEOF_PTR+3)) -
152  rtree->levels[level].cumulative_bits)) & ((ZU(1) <<
153  rtree->levels[level].bits) - 1));
154 }
155 
157 rtree_node_valid(rtree_node_elm_t *node)
158 {
159 
160  return ((uintptr_t)node > (uintptr_t)RTREE_NODE_INITIALIZING);
161 }
162 
163 JEMALLOC_ALWAYS_INLINE rtree_node_elm_t *
164 rtree_child_tryread(rtree_node_elm_t *elm, bool dependent)
165 {
166  rtree_node_elm_t *child;
167 
168  /* Double-checked read (first read may be stale. */
169  child = elm->child;
170  if (!dependent && !rtree_node_valid(child))
171  child = atomic_read_p(&elm->pun);
172  if (unlikely(dependent || child == NULL))
173  return (NULL);
174  return (child);
175 }
176 
177 JEMALLOC_ALWAYS_INLINE rtree_node_elm_t *
178 rtree_child_read(rtree_t *rtree, rtree_node_elm_t *elm, unsigned level,
179  bool dependent)
180 {
181  rtree_node_elm_t *child;
182 
183  child = rtree_child_tryread(elm, dependent);
184  if (!dependent && unlikely(!rtree_node_valid(child)))
185  child = rtree_child_read_hard(rtree, elm, level);
186  if (unlikely(dependent || child == NULL))
187  return (NULL);
188  return (child);
189 }
190 
191 JEMALLOC_ALWAYS_INLINE extent_node_t *
192 rtree_val_read(rtree_t *rtree, rtree_node_elm_t *elm, bool dependent)
193 {
194 
195  if (dependent) {
196  /*
197  * Reading a val on behalf of a pointer to a valid allocation is
198  * guaranteed to be a clean read even without synchronization,
199  * because the rtree update became visible in memory before the
200  * pointer came into existence.
201  */
202  return (elm->val);
203  } else {
204  /*
205  * An arbitrary read, e.g. on behalf of ivsalloc(), may not be
206  * dependent on a previous rtree write, which means a stale read
207  * could result if synchronization were omitted here.
208  */
209  return (atomic_read_p(&elm->pun));
210  }
211 }
212 
213 JEMALLOC_INLINE void
214 rtree_val_write(rtree_t *rtree, rtree_node_elm_t *elm, const extent_node_t *val)
215 {
216 
217  atomic_write_p(&elm->pun, val);
218 }
219 
220 JEMALLOC_ALWAYS_INLINE rtree_node_elm_t *
221 rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent)
222 {
223  rtree_node_elm_t *subtree;
224 
225  /* Double-checked read (first read may be stale. */
226  subtree = rtree->levels[level].subtree;
227  if (!dependent && unlikely(!rtree_node_valid(subtree)))
228  subtree = atomic_read_p(&rtree->levels[level].subtree_pun);
229 
230  if (unlikely(dependent || subtree == NULL))
231  return (NULL);
232  return (subtree);
233 }
234 
235 JEMALLOC_ALWAYS_INLINE rtree_node_elm_t *
236 rtree_subtree_read(rtree_t *rtree, unsigned level, bool dependent)
237 {
238  rtree_node_elm_t *subtree;
239 
240  subtree = rtree_subtree_tryread(rtree, level, dependent);
241  if (!dependent && unlikely(!rtree_node_valid(subtree)))
242  subtree = rtree_subtree_read_hard(rtree, level);
243  if (unlikely(dependent || subtree == NULL))
244  return (NULL);
245  return (subtree);
246 }
247 
248 JEMALLOC_ALWAYS_INLINE extent_node_t *
249 rtree_get(rtree_t *rtree, uintptr_t key, bool dependent)
250 {
251  uintptr_t subkey;
252  unsigned start_level;
253  rtree_node_elm_t *node;
254 
255  start_level = rtree_start_level(rtree, key);
256 
257  node = rtree_subtree_tryread(rtree, start_level, dependent);
258 #define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height)
259  switch (start_level + RTREE_GET_BIAS) {
260 #define RTREE_GET_SUBTREE(level) \
261  case level: \
262  if (unlikely(level > (RTREE_HEIGHT_MAX-1)))\
263  return (NULL)\
264  if (!dependent && unlikely(!rtree_node_valid(node))) \
265  return (NULL); \
266  subkey = rtree_subkey(rtree, key, level - \
267  RTREE_GET_BIAS); \
268  node = rtree_child_tryread(&node[subkey], dependent); \
269  /* Fall through. */
270 #define RTREE_GET_LEAF(level) \
271  case level: \
272  if (unlikely(level != (RTREE_HEIGHT_MAX-1))) \
273  return (NULL); \
274  if (!dependent && unlikely(!rtree_node_valid(node))) \
275  return (NULL); \
276  subkey = rtree_subkey(rtree, key, level - \
277  RTREE_GET_BIAS); \
278  /* \
279  * node is a leaf, so it contains values rather than \
280  * child pointers. \
281  */ \
282  return (rtree_val_read(rtree, &node[subkey], \
283  dependent));
284 #if RTREE_HEIGHT_MAX > 1
285  RTREE_GET_SUBTREE(0)
286 #endif
287 #if RTREE_HEIGHT_MAX > 2
288  RTREE_GET_SUBTREE(1)
289 #endif
290 #if RTREE_HEIGHT_MAX > 3
291  RTREE_GET_SUBTREE(2)
292 #endif
293 #if RTREE_HEIGHT_MAX > 4
294  RTREE_GET_SUBTREE(3)
295 #endif
296 #if RTREE_HEIGHT_MAX > 5
297  RTREE_GET_SUBTREE(4)
298 #endif
299 #if RTREE_HEIGHT_MAX > 6
300  RTREE_GET_SUBTREE(5)
301 #endif
302 #if RTREE_HEIGHT_MAX > 7
303  RTREE_GET_SUBTREE(6)
304 #endif
305 #if RTREE_HEIGHT_MAX > 8
306  RTREE_GET_SUBTREE(7)
307 #endif
308 #if RTREE_HEIGHT_MAX > 9
309  RTREE_GET_SUBTREE(8)
310 #endif
311 #if RTREE_HEIGHT_MAX > 10
312  RTREE_GET_SUBTREE(9)
313 #endif
314 #if RTREE_HEIGHT_MAX > 11
315  RTREE_GET_SUBTREE(10)
316 #endif
317 #if RTREE_HEIGHT_MAX > 12
318  RTREE_GET_SUBTREE(11)
319 #endif
320 #if RTREE_HEIGHT_MAX > 13
321  RTREE_GET_SUBTREE(12)
322 #endif
323 #if RTREE_HEIGHT_MAX > 14
324  RTREE_GET_SUBTREE(13)
325 #endif
326 #if RTREE_HEIGHT_MAX > 15
327  RTREE_GET_SUBTREE(14)
328 #endif
329 #if RTREE_HEIGHT_MAX > 16
330 # error Unsupported RTREE_HEIGHT_MAX
331 #endif
332  RTREE_GET_LEAF(RTREE_HEIGHT_MAX-1)
333 #undef RTREE_GET_SUBTREE
334 #undef RTREE_GET_LEAF
335  default: not_reached();
336  }
337 #undef RTREE_GET_BIAS
338  not_reached();
339 }
340 
341 JEMALLOC_INLINE bool
342 rtree_set(rtree_t *rtree, uintptr_t key, const extent_node_t *val)
343 {
344  uintptr_t subkey;
345  unsigned i, start_level;
346  rtree_node_elm_t *node, *child;
347 
348  start_level = rtree_start_level(rtree, key);
349 
350  node = rtree_subtree_read(rtree, start_level, false);
351  if (node == NULL)
352  return (true);
353  for (i = start_level; ; i++, node = child) {
354  subkey = rtree_subkey(rtree, key, i);
355  if (i == rtree->height - 1) {
356  /*
357  * node is a leaf, so it contains values rather than
358  * child pointers.
359  */
360  rtree_val_write(rtree, &node[subkey], val);
361  return (false);
362  }
363  if (unlikely (i + 1 > rtree->height))
364  return (false);
365  child = rtree_child_read(rtree, &node[subkey], i, false);
366  if (child == NULL)
367  return (true);
368  }
369  not_reached();
370 }
371 #endif
372 
373 #endif /* JEMALLOC_H_INLINES */
374 /******************************************************************************/
lzma_index ** i
Definition: index.h:629
ut16 val
Definition: armass64_const.h:6
#define not_reached()
Definition: assert.h:17
int bits(struct state *s, int need)
Definition: blast.c:72
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len key
Definition: sflib.h:118
#define LG_SIZEOF_PTR
Definition: jemalloc.h:51
#define JEMALLOC_INLINE
#define ZU(z)
#define JEMALLOC_ALWAYS_INLINE
#define unlikely(expr)
Definition: lz4.c:177
assert(limit<=UINT32_MAX/2)
#define rtree_subkey
#define rtree_delete
#define rtree_subtree_read
#define rtree_start_level
#define atomic_write_p
#define rtree_new
#define rtree_subtree_read_hard
#define rtree_subtree_tryread
#define rtree_val_read
#define rtree_child_read_hard
#define lg_floor
#define rtree_set
#define rtree_child_read
#define rtree_val_write
#define rtree_get
#define rtree_node_valid
#define rtree_child_tryread
_W64 unsigned int uintptr_t
int height
Definition: main.c:10
static int level
Definition: vmenus.c:2424