1 1.1 mrg /* Lock-free btree for manually registered unwind frames. */ 2 1.1 mrg /* Copyright (C) 2022-2024 Free Software Foundation, Inc. 3 1.1 mrg Contributed by Thomas Neumann 4 1.1 mrg 5 1.1 mrg This file is part of GCC. 6 1.1 mrg 7 1.1 mrg GCC is free software; you can redistribute it and/or modify it under 8 1.1 mrg the terms of the GNU General Public License as published by the Free 9 1.1 mrg Software Foundation; either version 3, or (at your option) any later 10 1.1 mrg version. 11 1.1 mrg 12 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 1.1 mrg for more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg #ifndef GCC_UNWIND_DW2_BTREE_H 27 1.1 mrg #define GCC_UNWIND_DW2_BTREE_H 28 1.1 mrg 29 1.1 mrg #include <stdbool.h> 30 1.1 mrg 31 1.1 mrg // Common logic for version locks. 32 1.1 mrg struct version_lock 33 1.1 mrg { 34 1.1 mrg // The lock itself. The lowest bit indicates an exclusive lock, 35 1.1 mrg // the second bit indicates waiting threads. All other bits are 36 1.1 mrg // used as counter to recognize changes. 37 1.1 mrg // Overflows are okay here, we must only prevent overflow to the 38 1.1 mrg // same value within one lock_optimistic/validate 39 1.1 mrg // range. Even on 32 bit platforms that would require 1 billion 40 1.1 mrg // frame registrations within the time span of a few assembler 41 1.1 mrg // instructions. 42 1.1 mrg uintptr_type version_lock; 43 1.1 mrg }; 44 1.1 mrg 45 1.1 mrg #ifdef __GTHREAD_HAS_COND 46 1.1 mrg // We should never get contention within the tree as it rarely changes. 47 1.1 mrg // But if we ever do get contention we use these for waiting. 48 1.1 mrg static __gthread_mutex_t version_lock_mutex = __GTHREAD_MUTEX_INIT; 49 1.1 mrg static __gthread_cond_t version_lock_cond = __GTHREAD_COND_INIT; 50 1.1 mrg #endif 51 1.1 mrg 52 1.1 mrg // Initialize in locked state. 53 1.1 mrg static inline void 54 1.1 mrg version_lock_initialize_locked_exclusive (struct version_lock *vl) 55 1.1 mrg { 56 1.1 mrg vl->version_lock = 1; 57 1.1 mrg } 58 1.1 mrg 59 1.1 mrg // Try to lock the node exclusive. 60 1.1 mrg static inline bool 61 1.1 mrg version_lock_try_lock_exclusive (struct version_lock *vl) 62 1.1 mrg { 63 1.1 mrg uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST); 64 1.1 mrg if (state & 1) 65 1.1 mrg return false; 66 1.1 mrg return __atomic_compare_exchange_n (&(vl->version_lock), &state, state | 1, 67 1.1 mrg false, __ATOMIC_SEQ_CST, 68 1.1 mrg __ATOMIC_SEQ_CST); 69 1.1 mrg } 70 1.1 mrg 71 1.1 mrg // Lock the node exclusive, blocking as needed. 72 1.1 mrg static void 73 1.1 mrg version_lock_lock_exclusive (struct version_lock *vl) 74 1.1 mrg { 75 1.1 mrg #ifndef __GTHREAD_HAS_COND 76 1.1 mrg restart: 77 1.1 mrg #endif 78 1.1 mrg 79 1.1 mrg // We should virtually never get contention here, as frame 80 1.1 mrg // changes are rare. 81 1.1 mrg uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST); 82 1.1 mrg if (!(state & 1)) 83 1.1 mrg { 84 1.1 mrg if (__atomic_compare_exchange_n (&(vl->version_lock), &state, state | 1, 85 1.1 mrg false, __ATOMIC_SEQ_CST, 86 1.1 mrg __ATOMIC_SEQ_CST)) 87 1.1 mrg return; 88 1.1 mrg } 89 1.1 mrg 90 1.1 mrg // We did get contention, wait properly. 91 1.1 mrg #ifdef __GTHREAD_HAS_COND 92 1.1 mrg __gthread_mutex_lock (&version_lock_mutex); 93 1.1 mrg state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST); 94 1.1 mrg while (true) 95 1.1 mrg { 96 1.1 mrg // Check if the lock is still held. 97 1.1 mrg if (!(state & 1)) 98 1.1 mrg { 99 1.1 mrg if (__atomic_compare_exchange_n (&(vl->version_lock), &state, 100 1.1 mrg state | 1, false, __ATOMIC_SEQ_CST, 101 1.1 mrg __ATOMIC_SEQ_CST)) 102 1.1 mrg { 103 1.1 mrg __gthread_mutex_unlock (&version_lock_mutex); 104 1.1 mrg return; 105 1.1 mrg } 106 1.1 mrg else 107 1.1 mrg { 108 1.1 mrg continue; 109 1.1 mrg } 110 1.1 mrg } 111 1.1 mrg 112 1.1 mrg // Register waiting thread. 113 1.1 mrg if (!(state & 2)) 114 1.1 mrg { 115 1.1 mrg if (!__atomic_compare_exchange_n (&(vl->version_lock), &state, 116 1.1 mrg state | 2, false, __ATOMIC_SEQ_CST, 117 1.1 mrg __ATOMIC_SEQ_CST)) 118 1.1 mrg continue; 119 1.1 mrg } 120 1.1 mrg 121 1.1 mrg // And sleep. 122 1.1 mrg __gthread_cond_wait (&version_lock_cond, &version_lock_mutex); 123 1.1 mrg state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST); 124 1.1 mrg } 125 1.1 mrg #else 126 1.1 mrg // Spin if we do not have condition variables available. 127 1.1 mrg // We expect no contention here, spinning should be okay. 128 1.1 mrg goto restart; 129 1.1 mrg #endif 130 1.1 mrg } 131 1.1 mrg 132 1.1 mrg // Release a locked node and increase the version lock. 133 1.1 mrg static void 134 1.1 mrg version_lock_unlock_exclusive (struct version_lock *vl) 135 1.1 mrg { 136 1.1 mrg // increase version, reset exclusive lock bits 137 1.1 mrg uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST); 138 1.1 mrg uintptr_type ns = (state + 4) & (~((uintptr_type) 3)); 139 1.1 mrg state = __atomic_exchange_n (&(vl->version_lock), ns, __ATOMIC_SEQ_CST); 140 1.1 mrg 141 1.1 mrg #ifdef __GTHREAD_HAS_COND 142 1.1 mrg if (state & 2) 143 1.1 mrg { 144 1.1 mrg // Wake up waiting threads. This should be extremely rare. 145 1.1 mrg __gthread_mutex_lock (&version_lock_mutex); 146 1.1 mrg __gthread_cond_broadcast (&version_lock_cond); 147 1.1 mrg __gthread_mutex_unlock (&version_lock_mutex); 148 1.1 mrg } 149 1.1 mrg #endif 150 1.1 mrg } 151 1.1 mrg 152 1.1 mrg // Acquire an optimistic "lock". Note that this does not lock at all, it 153 1.1 mrg // only allows for validation later. 154 1.1 mrg static inline bool 155 1.1 mrg version_lock_lock_optimistic (const struct version_lock *vl, uintptr_type *lock) 156 1.1 mrg { 157 1.1 mrg uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST); 158 1.1 mrg *lock = state; 159 1.1 mrg 160 1.1 mrg // Acquiring the lock fails when there is currently an exclusive lock. 161 1.1 mrg return !(state & 1); 162 1.1 mrg } 163 1.1 mrg 164 1.1 mrg // Validate a previously acquired "lock". 165 1.1 mrg static inline bool 166 1.1 mrg version_lock_validate (const struct version_lock *vl, uintptr_type lock) 167 1.1 mrg { 168 1.1 mrg // Prevent the reordering of non-atomic loads behind the atomic load. 169 1.1 mrg // Hans Boehm, Can Seqlocks Get Along with Programming Language Memory 170 1.1 mrg // Models?, Section 4. 171 1.1 mrg __atomic_thread_fence (__ATOMIC_ACQUIRE); 172 1.1 mrg 173 1.1 mrg // Check that the node is still in the same state. 174 1.1 mrg uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST); 175 1.1 mrg return (state == lock); 176 1.1 mrg } 177 1.1 mrg 178 1.1 mrg // The largest possible separator value. 179 1.1 mrg static const uintptr_type max_separator = ~((uintptr_type) (0)); 180 1.1 mrg 181 1.1 mrg struct btree_node; 182 1.1 mrg 183 1.1 mrg // Inner entry. The child tree contains all entries <= separator. 184 1.1 mrg struct inner_entry 185 1.1 mrg { 186 1.1 mrg uintptr_type separator; 187 1.1 mrg struct btree_node *child; 188 1.1 mrg }; 189 1.1 mrg 190 1.1 mrg // Leaf entry. Stores an object entry. 191 1.1 mrg struct leaf_entry 192 1.1 mrg { 193 1.1 mrg uintptr_type base, size; 194 1.1 mrg struct object *ob; 195 1.1 mrg }; 196 1.1 mrg 197 1.1 mrg // Node types. 198 1.1 mrg enum node_type 199 1.1 mrg { 200 1.1 mrg btree_node_inner, 201 1.1 mrg btree_node_leaf, 202 1.1 mrg btree_node_free 203 1.1 mrg }; 204 1.1 mrg 205 1.1 mrg // Node sizes. Chosen such that the result size is roughly 256 bytes. 206 1.1 mrg #define max_fanout_inner 15 207 1.1 mrg #define max_fanout_leaf 10 208 1.1 mrg 209 1.1 mrg // A btree node. 210 1.1 mrg struct btree_node 211 1.1 mrg { 212 1.1 mrg // The version lock used for optimistic lock coupling. 213 1.1 mrg struct version_lock version_lock; 214 1.1 mrg // The number of entries. 215 1.1 mrg unsigned entry_count; 216 1.1 mrg // The type. 217 1.1 mrg enum node_type type; 218 1.1 mrg // The payload. 219 1.1 mrg union 220 1.1 mrg { 221 1.1 mrg // The inner nodes have fence keys, i.e., the right-most entry includes a 222 1.1 mrg // separator. 223 1.1 mrg struct inner_entry children[max_fanout_inner]; 224 1.1 mrg struct leaf_entry entries[max_fanout_leaf]; 225 1.1 mrg } content; 226 1.1 mrg }; 227 1.1 mrg 228 1.1 mrg // Is an inner node? 229 1.1 mrg static inline bool 230 1.1 mrg btree_node_is_inner (const struct btree_node *n) 231 1.1 mrg { 232 1.1 mrg return n->type == btree_node_inner; 233 1.1 mrg } 234 1.1 mrg 235 1.1 mrg // Is a leaf node? 236 1.1 mrg static inline bool 237 1.1 mrg btree_node_is_leaf (const struct btree_node *n) 238 1.1 mrg { 239 1.1 mrg return n->type == btree_node_leaf; 240 1.1 mrg } 241 1.1 mrg 242 1.1 mrg // Should the node be merged? 243 1.1 mrg static inline bool 244 1.1 mrg btree_node_needs_merge (const struct btree_node *n) 245 1.1 mrg { 246 1.1 mrg return n->entry_count < (btree_node_is_inner (n) ? (max_fanout_inner / 2) 247 1.1 mrg : (max_fanout_leaf / 2)); 248 1.1 mrg } 249 1.1 mrg 250 1.1 mrg // Get the fence key for inner nodes. 251 1.1 mrg static inline uintptr_type 252 1.1 mrg btree_node_get_fence_key (const struct btree_node *n) 253 1.1 mrg { 254 1.1 mrg // For inner nodes we just return our right-most entry. 255 1.1 mrg return n->content.children[n->entry_count - 1].separator; 256 1.1 mrg } 257 1.1 mrg 258 1.1 mrg // Find the position for a slot in an inner node. 259 1.1 mrg static unsigned 260 1.1 mrg btree_node_find_inner_slot (const struct btree_node *n, uintptr_type value) 261 1.1 mrg { 262 1.1 mrg for (unsigned index = 0, ec = n->entry_count; index != ec; ++index) 263 1.1 mrg if (n->content.children[index].separator >= value) 264 1.1 mrg return index; 265 1.1 mrg return n->entry_count; 266 1.1 mrg } 267 1.1 mrg 268 1.1 mrg // Find the position for a slot in a leaf node. 269 1.1 mrg static unsigned 270 1.1 mrg btree_node_find_leaf_slot (const struct btree_node *n, uintptr_type value) 271 1.1 mrg { 272 1.1 mrg for (unsigned index = 0, ec = n->entry_count; index != ec; ++index) 273 1.1 mrg if (n->content.entries[index].base + n->content.entries[index].size > value) 274 1.1 mrg return index; 275 1.1 mrg return n->entry_count; 276 1.1 mrg } 277 1.1 mrg 278 1.1 mrg // Try to lock the node exclusive. 279 1.1 mrg static inline bool 280 1.1 mrg btree_node_try_lock_exclusive (struct btree_node *n) 281 1.1 mrg { 282 1.1 mrg return version_lock_try_lock_exclusive (&(n->version_lock)); 283 1.1 mrg } 284 1.1 mrg 285 1.1 mrg // Lock the node exclusive, blocking as needed. 286 1.1 mrg static inline void 287 1.1 mrg btree_node_lock_exclusive (struct btree_node *n) 288 1.1 mrg { 289 1.1 mrg version_lock_lock_exclusive (&(n->version_lock)); 290 1.1 mrg } 291 1.1 mrg 292 1.1 mrg // Release a locked node and increase the version lock. 293 1.1 mrg static inline void 294 1.1 mrg btree_node_unlock_exclusive (struct btree_node *n) 295 1.1 mrg { 296 1.1 mrg version_lock_unlock_exclusive (&(n->version_lock)); 297 1.1 mrg } 298 1.1 mrg 299 1.1 mrg // Acquire an optimistic "lock". Note that this does not lock at all, it 300 1.1 mrg // only allows for validation later. 301 1.1 mrg static inline bool 302 1.1 mrg btree_node_lock_optimistic (const struct btree_node *n, uintptr_type *lock) 303 1.1 mrg { 304 1.1 mrg return version_lock_lock_optimistic (&(n->version_lock), lock); 305 1.1 mrg } 306 1.1 mrg 307 1.1 mrg // Validate a previously acquire lock. 308 1.1 mrg static inline bool 309 1.1 mrg btree_node_validate (const struct btree_node *n, uintptr_type lock) 310 1.1 mrg { 311 1.1 mrg return version_lock_validate (&(n->version_lock), lock); 312 1.1 mrg } 313 1.1 mrg 314 1.1 mrg // Insert a new separator after splitting. 315 1.1 mrg static void 316 1.1 mrg btree_node_update_separator_after_split (struct btree_node *n, 317 1.1 mrg uintptr_type old_separator, 318 1.1 mrg uintptr_type new_separator, 319 1.1 mrg struct btree_node *new_right) 320 1.1 mrg { 321 1.1 mrg unsigned slot = btree_node_find_inner_slot (n, old_separator); 322 1.1 mrg for (unsigned index = n->entry_count; index > slot; --index) 323 1.1 mrg n->content.children[index] = n->content.children[index - 1]; 324 1.1 mrg n->content.children[slot].separator = new_separator; 325 1.1 mrg n->content.children[slot + 1].child = new_right; 326 1.1 mrg n->entry_count++; 327 1.1 mrg } 328 1.1 mrg 329 1.1 mrg // A btree. Suitable for static initialization, all members are zero at the 330 1.1 mrg // beginning. 331 1.1 mrg struct btree 332 1.1 mrg { 333 1.1 mrg // The root of the btree. 334 1.1 mrg struct btree_node *root; 335 1.1 mrg // The free list of released node. 336 1.1 mrg struct btree_node *free_list; 337 1.1 mrg // The version lock used to protect the root. 338 1.1 mrg struct version_lock root_lock; 339 1.1 mrg }; 340 1.1 mrg 341 1.1 mrg // Initialize a btree. Not actually used, just for exposition. 342 1.1 mrg static inline void 343 1.1 mrg btree_init (struct btree *t) 344 1.1 mrg { 345 1.1 mrg t->root = NULL; 346 1.1 mrg t->free_list = NULL; 347 1.1 mrg t->root_lock.version_lock = 0; 348 1.1 mrg }; 349 1.1 mrg 350 1.1 mrg static void 351 1.1 mrg btree_release_tree_recursively (struct btree *t, struct btree_node *n); 352 1.1 mrg 353 1.1 mrg // Destroy a tree and release all nodes. 354 1.1 mrg static void 355 1.1 mrg btree_destroy (struct btree *t) 356 1.1 mrg { 357 1.1 mrg // Disable the mechanism before cleaning up. 358 1.1 mrg struct btree_node *old_root 359 1.1 mrg = __atomic_exchange_n (&(t->root), NULL, __ATOMIC_SEQ_CST); 360 1.1 mrg if (old_root) 361 1.1 mrg btree_release_tree_recursively (t, old_root); 362 1.1 mrg 363 1.1 mrg // Release all free nodes. 364 1.1 mrg while (t->free_list) 365 1.1 mrg { 366 1.1 mrg struct btree_node *next = t->free_list->content.children[0].child; 367 1.1 mrg free (t->free_list); 368 1.1 mrg t->free_list = next; 369 1.1 mrg } 370 1.1 mrg } 371 1.1 mrg 372 1.1 mrg // Allocate a node. This node will be returned in locked exclusive state. 373 1.1 mrg static struct btree_node * 374 1.1 mrg btree_allocate_node (struct btree *t, bool inner) 375 1.1 mrg { 376 1.1 mrg while (true) 377 1.1 mrg { 378 1.1 mrg // Try the free list first. 379 1.1 mrg struct btree_node *next_free 380 1.1 mrg = __atomic_load_n (&(t->free_list), __ATOMIC_SEQ_CST); 381 1.1 mrg if (next_free) 382 1.1 mrg { 383 1.1 mrg if (!btree_node_try_lock_exclusive (next_free)) 384 1.1 mrg continue; 385 1.1 mrg // The node might no longer be free, check that again after acquiring 386 1.1 mrg // the exclusive lock. 387 1.1 mrg if (next_free->type == btree_node_free) 388 1.1 mrg { 389 1.1 mrg struct btree_node *ex = next_free; 390 1.1 mrg if (__atomic_compare_exchange_n ( 391 1.1 mrg &(t->free_list), &ex, next_free->content.children[0].child, 392 1.1 mrg false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) 393 1.1 mrg { 394 1.1 mrg next_free->entry_count = 0; 395 1.1 mrg next_free->type = inner ? btree_node_inner : btree_node_leaf; 396 1.1 mrg return next_free; 397 1.1 mrg } 398 1.1 mrg } 399 1.1 mrg btree_node_unlock_exclusive (next_free); 400 1.1 mrg continue; 401 1.1 mrg } 402 1.1 mrg 403 1.1 mrg // No free node available, allocate a new one. 404 1.1 mrg struct btree_node *new_node 405 1.1 mrg = (struct btree_node *) (malloc (sizeof (struct btree_node))); 406 1.1 mrg version_lock_initialize_locked_exclusive ( 407 1.1 mrg &(new_node->version_lock)); // initialize the node in locked state. 408 1.1 mrg new_node->entry_count = 0; 409 1.1 mrg new_node->type = inner ? btree_node_inner : btree_node_leaf; 410 1.1 mrg return new_node; 411 1.1 mrg } 412 1.1 mrg } 413 1.1 mrg 414 1.1 mrg // Release a node. This node must be currently locked exclusively and will 415 1.1 mrg // be placed in the free list. 416 1.1 mrg static void 417 1.1 mrg btree_release_node (struct btree *t, struct btree_node *node) 418 1.1 mrg { 419 1.1 mrg // We cannot release the memory immediately because there might still be 420 1.1 mrg // concurrent readers on that node. Put it in the free list instead. 421 1.1 mrg node->type = btree_node_free; 422 1.1 mrg struct btree_node *next_free 423 1.1 mrg = __atomic_load_n (&(t->free_list), __ATOMIC_SEQ_CST); 424 1.1 mrg do 425 1.1 mrg { 426 1.1 mrg node->content.children[0].child = next_free; 427 1.1 mrg } while (!__atomic_compare_exchange_n (&(t->free_list), &next_free, node, 428 1.1 mrg false, __ATOMIC_SEQ_CST, 429 1.1 mrg __ATOMIC_SEQ_CST)); 430 1.1 mrg btree_node_unlock_exclusive (node); 431 1.1 mrg } 432 1.1 mrg 433 1.1 mrg // Recursively release a tree. The btree is by design very shallow, thus 434 1.1 mrg // we can risk recursion here. 435 1.1 mrg static void 436 1.1 mrg btree_release_tree_recursively (struct btree *t, struct btree_node *node) 437 1.1 mrg { 438 1.1 mrg btree_node_lock_exclusive (node); 439 1.1 mrg if (btree_node_is_inner (node)) 440 1.1 mrg { 441 1.1 mrg for (unsigned index = 0; index < node->entry_count; ++index) 442 1.1 mrg btree_release_tree_recursively (t, node->content.children[index].child); 443 1.1 mrg } 444 1.1 mrg btree_release_node (t, node); 445 1.1 mrg } 446 1.1 mrg 447 1.1 mrg // Check if we are splitting the root. 448 1.1 mrg static void 449 1.1 mrg btree_handle_root_split (struct btree *t, struct btree_node **node, 450 1.1 mrg struct btree_node **parent) 451 1.1 mrg { 452 1.1 mrg // We want to keep the root pointer stable to allow for contention 453 1.1 mrg // free reads. Thus, we split the root by first moving the content 454 1.1 mrg // of the root node to a new node, and then split that new node. 455 1.1 mrg if (!*parent) 456 1.1 mrg { 457 1.1 mrg // Allocate a new node, this guarantees us that we will have a parent 458 1.1 mrg // afterwards. 459 1.1 mrg struct btree_node *new_node 460 1.1 mrg = btree_allocate_node (t, btree_node_is_inner (*node)); 461 1.1 mrg struct btree_node *old_node = *node; 462 1.1 mrg new_node->entry_count = old_node->entry_count; 463 1.1 mrg new_node->content = old_node->content; 464 1.1 mrg old_node->content.children[0].separator = max_separator; 465 1.1 mrg old_node->content.children[0].child = new_node; 466 1.1 mrg old_node->entry_count = 1; 467 1.1 mrg old_node->type = btree_node_inner; 468 1.1 mrg 469 1.1 mrg *parent = old_node; 470 1.1 mrg *node = new_node; 471 1.1 mrg } 472 1.1 mrg } 473 1.1 mrg 474 1.1 mrg // Split an inner node. 475 1.1 mrg static void 476 1.1 mrg btree_split_inner (struct btree *t, struct btree_node **inner, 477 1.1 mrg struct btree_node **parent, uintptr_type target, 478 1.1 mrg uintptr_type size) 479 1.1 mrg { 480 1.1 mrg // Check for the root. 481 1.1 mrg btree_handle_root_split (t, inner, parent); 482 1.1 mrg 483 1.1 mrg // Create two inner node. 484 1.1 mrg uintptr_type right_fence = btree_node_get_fence_key (*inner); 485 1.1 mrg struct btree_node *left_inner = *inner; 486 1.1 mrg struct btree_node *right_inner = btree_allocate_node (t, true); 487 1.1 mrg unsigned split = left_inner->entry_count / 2; 488 1.1 mrg right_inner->entry_count = left_inner->entry_count - split; 489 1.1 mrg for (unsigned index = 0; index < right_inner->entry_count; ++index) 490 1.1 mrg right_inner->content.children[index] 491 1.1 mrg = left_inner->content.children[split + index]; 492 1.1 mrg left_inner->entry_count = split; 493 1.1 mrg uintptr_type left_fence = btree_node_get_fence_key (left_inner); 494 1.1 mrg if (left_fence >= target && left_fence < target + size - 1) 495 1.1 mrg // See the PR119151 comment in btree_insert. 496 1.1 mrg left_fence = target + size - 1; 497 1.1 mrg btree_node_update_separator_after_split (*parent, right_fence, left_fence, 498 1.1 mrg right_inner); 499 1.1 mrg if (target <= left_fence) 500 1.1 mrg { 501 1.1 mrg *inner = left_inner; 502 1.1 mrg btree_node_unlock_exclusive (right_inner); 503 1.1 mrg } 504 1.1 mrg else 505 1.1 mrg { 506 1.1 mrg *inner = right_inner; 507 1.1 mrg btree_node_unlock_exclusive (left_inner); 508 1.1 mrg } 509 1.1 mrg } 510 1.1 mrg 511 1.1 mrg // Split a leaf node. 512 1.1 mrg static void 513 1.1 mrg btree_split_leaf (struct btree *t, struct btree_node **leaf, 514 1.1 mrg struct btree_node **parent, uintptr_type fence, 515 1.1 mrg uintptr_type target) 516 1.1 mrg { 517 1.1 mrg // Check for the root. 518 1.1 mrg btree_handle_root_split (t, leaf, parent); 519 1.1 mrg 520 1.1 mrg // Create two leaf nodes. 521 1.1 mrg uintptr_type right_fence = fence; 522 1.1 mrg struct btree_node *left_leaf = *leaf; 523 1.1 mrg struct btree_node *right_leaf = btree_allocate_node (t, false); 524 1.1 mrg unsigned split = left_leaf->entry_count / 2; 525 1.1 mrg right_leaf->entry_count = left_leaf->entry_count - split; 526 1.1 mrg for (unsigned index = 0; index != right_leaf->entry_count; ++index) 527 1.1 mrg right_leaf->content.entries[index] 528 1.1 mrg = left_leaf->content.entries[split + index]; 529 1.1 mrg left_leaf->entry_count = split; 530 1.1 mrg uintptr_type left_fence = right_leaf->content.entries[0].base - 1; 531 1.1 mrg btree_node_update_separator_after_split (*parent, right_fence, left_fence, 532 1.1 mrg right_leaf); 533 1.1 mrg if (target <= left_fence) 534 1.1 mrg { 535 1.1 mrg *leaf = left_leaf; 536 1.1 mrg btree_node_unlock_exclusive (right_leaf); 537 1.1 mrg } 538 1.1 mrg else 539 1.1 mrg { 540 1.1 mrg *leaf = right_leaf; 541 1.1 mrg btree_node_unlock_exclusive (left_leaf); 542 1.1 mrg } 543 1.1 mrg } 544 1.1 mrg 545 1.1 mrg // Merge (or balance) child nodes. 546 1.1 mrg static struct btree_node * 547 1.1 mrg btree_merge_node (struct btree *t, unsigned child_slot, 548 1.1 mrg struct btree_node *parent, uintptr_type target) 549 1.1 mrg { 550 1.1 mrg // Choose the emptiest neighbor and lock both. The target child is already 551 1.1 mrg // locked. 552 1.1 mrg unsigned left_slot; 553 1.1 mrg struct btree_node *left_node, *right_node; 554 1.1 mrg if ((child_slot == 0) 555 1.1 mrg || (((child_slot + 1) < parent->entry_count) 556 1.1 mrg && (parent->content.children[child_slot + 1].child->entry_count 557 1.1 mrg < parent->content.children[child_slot - 1].child->entry_count))) 558 1.1 mrg { 559 1.1 mrg left_slot = child_slot; 560 1.1 mrg left_node = parent->content.children[left_slot].child; 561 1.1 mrg right_node = parent->content.children[left_slot + 1].child; 562 1.1 mrg btree_node_lock_exclusive (right_node); 563 1.1 mrg } 564 1.1 mrg else 565 1.1 mrg { 566 1.1 mrg left_slot = child_slot - 1; 567 1.1 mrg left_node = parent->content.children[left_slot].child; 568 1.1 mrg right_node = parent->content.children[left_slot + 1].child; 569 1.1 mrg btree_node_lock_exclusive (left_node); 570 1.1 mrg } 571 1.1 mrg 572 1.1 mrg // Can we merge both nodes into one node? 573 1.1 mrg unsigned total_count = left_node->entry_count + right_node->entry_count; 574 1.1 mrg unsigned max_count 575 1.1 mrg = btree_node_is_inner (left_node) ? max_fanout_inner : max_fanout_leaf; 576 1.1 mrg if (total_count <= max_count) 577 1.1 mrg { 578 1.1 mrg // Merge into the parent? 579 1.1 mrg if (parent->entry_count == 2) 580 1.1 mrg { 581 1.1 mrg // Merge children into parent. This can only happen at the root. 582 1.1 mrg if (btree_node_is_inner (left_node)) 583 1.1 mrg { 584 1.1 mrg for (unsigned index = 0; index != left_node->entry_count; ++index) 585 1.1 mrg parent->content.children[index] 586 1.1 mrg = left_node->content.children[index]; 587 1.1 mrg for (unsigned index = 0; index != right_node->entry_count; 588 1.1 mrg ++index) 589 1.1 mrg parent->content.children[index + left_node->entry_count] 590 1.1 mrg = right_node->content.children[index]; 591 1.1 mrg } 592 1.1 mrg else 593 1.1 mrg { 594 1.1 mrg parent->type = btree_node_leaf; 595 1.1 mrg for (unsigned index = 0; index != left_node->entry_count; ++index) 596 1.1 mrg parent->content.entries[index] 597 1.1 mrg = left_node->content.entries[index]; 598 1.1 mrg for (unsigned index = 0; index != right_node->entry_count; 599 1.1 mrg ++index) 600 1.1 mrg parent->content.entries[index + left_node->entry_count] 601 1.1 mrg = right_node->content.entries[index]; 602 1.1 mrg } 603 1.1 mrg parent->entry_count = total_count; 604 1.1 mrg btree_release_node (t, left_node); 605 1.1 mrg btree_release_node (t, right_node); 606 1.1 mrg return parent; 607 1.1 mrg } 608 1.1 mrg else 609 1.1 mrg { 610 1.1 mrg // Regular merge. 611 1.1 mrg if (btree_node_is_inner (left_node)) 612 1.1 mrg { 613 1.1 mrg for (unsigned index = 0; index != right_node->entry_count; 614 1.1 mrg ++index) 615 1.1 mrg left_node->content.children[left_node->entry_count++] 616 1.1 mrg = right_node->content.children[index]; 617 1.1 mrg } 618 1.1 mrg else 619 1.1 mrg { 620 1.1 mrg for (unsigned index = 0; index != right_node->entry_count; 621 1.1 mrg ++index) 622 1.1 mrg left_node->content.entries[left_node->entry_count++] 623 1.1 mrg = right_node->content.entries[index]; 624 1.1 mrg } 625 1.1 mrg parent->content.children[left_slot].separator 626 1.1 mrg = parent->content.children[left_slot + 1].separator; 627 1.1 mrg for (unsigned index = left_slot + 1; index + 1 < parent->entry_count; 628 1.1 mrg ++index) 629 1.1 mrg parent->content.children[index] 630 1.1 mrg = parent->content.children[index + 1]; 631 1.1 mrg parent->entry_count--; 632 1.1 mrg btree_release_node (t, right_node); 633 1.1 mrg btree_node_unlock_exclusive (parent); 634 1.1 mrg return left_node; 635 1.1 mrg } 636 1.1 mrg } 637 1.1 mrg 638 1.1 mrg // No merge possible, rebalance instead. 639 1.1 mrg if (left_node->entry_count > right_node->entry_count) 640 1.1 mrg { 641 1.1 mrg // Shift from left to right. 642 1.1 mrg unsigned to_shift 643 1.1 mrg = (left_node->entry_count - right_node->entry_count) / 2; 644 1.1 mrg if (btree_node_is_inner (left_node)) 645 1.1 mrg { 646 1.1 mrg for (unsigned index = 0; index != right_node->entry_count; ++index) 647 1.1 mrg { 648 1.1 mrg unsigned pos = right_node->entry_count - 1 - index; 649 1.1 mrg right_node->content.children[pos + to_shift] 650 1.1 mrg = right_node->content.children[pos]; 651 1.1 mrg } 652 1.1 mrg for (unsigned index = 0; index != to_shift; ++index) 653 1.1 mrg right_node->content.children[index] 654 1.1 mrg = left_node->content 655 1.1 mrg .children[left_node->entry_count - to_shift + index]; 656 1.1 mrg } 657 1.1 mrg else 658 1.1 mrg { 659 1.1 mrg for (unsigned index = 0; index != right_node->entry_count; ++index) 660 1.1 mrg { 661 1.1 mrg unsigned pos = right_node->entry_count - 1 - index; 662 1.1 mrg right_node->content.entries[pos + to_shift] 663 1.1 mrg = right_node->content.entries[pos]; 664 1.1 mrg } 665 1.1 mrg for (unsigned index = 0; index != to_shift; ++index) 666 1.1 mrg right_node->content.entries[index] 667 1.1 mrg = left_node->content 668 1.1 mrg .entries[left_node->entry_count - to_shift + index]; 669 1.1 mrg } 670 1.1 mrg left_node->entry_count -= to_shift; 671 1.1 mrg right_node->entry_count += to_shift; 672 1.1 mrg } 673 1.1 mrg else 674 1.1 mrg { 675 1.1 mrg // Shift from right to left. 676 1.1 mrg unsigned to_shift 677 1.1 mrg = (right_node->entry_count - left_node->entry_count) / 2; 678 1.1 mrg if (btree_node_is_inner (left_node)) 679 1.1 mrg { 680 1.1 mrg for (unsigned index = 0; index != to_shift; ++index) 681 1.1 mrg left_node->content.children[left_node->entry_count + index] 682 1.1 mrg = right_node->content.children[index]; 683 1.1 mrg for (unsigned index = 0; index != right_node->entry_count - to_shift; 684 1.1 mrg ++index) 685 1.1 mrg right_node->content.children[index] 686 1.1 mrg = right_node->content.children[index + to_shift]; 687 1.1 mrg } 688 1.1 mrg else 689 1.1 mrg { 690 1.1 mrg for (unsigned index = 0; index != to_shift; ++index) 691 1.1 mrg left_node->content.entries[left_node->entry_count + index] 692 1.1 mrg = right_node->content.entries[index]; 693 1.1 mrg for (unsigned index = 0; index != right_node->entry_count - to_shift; 694 1.1 mrg ++index) 695 1.1 mrg right_node->content.entries[index] 696 1.1 mrg = right_node->content.entries[index + to_shift]; 697 1.1 mrg } 698 1.1 mrg left_node->entry_count += to_shift; 699 1.1 mrg right_node->entry_count -= to_shift; 700 1.1 mrg } 701 1.1 mrg uintptr_type left_fence; 702 1.1 mrg if (btree_node_is_leaf (left_node)) 703 1.1 mrg { 704 1.1 mrg left_fence = right_node->content.entries[0].base - 1; 705 1.1 mrg } 706 1.1 mrg else 707 1.1 mrg { 708 1.1 mrg left_fence = btree_node_get_fence_key (left_node); 709 1.1 mrg } 710 1.1 mrg parent->content.children[left_slot].separator = left_fence; 711 1.1 mrg btree_node_unlock_exclusive (parent); 712 1.1 mrg if (target <= left_fence) 713 1.1 mrg { 714 1.1 mrg btree_node_unlock_exclusive (right_node); 715 1.1 mrg return left_node; 716 1.1 mrg } 717 1.1 mrg else 718 1.1 mrg { 719 1.1 mrg btree_node_unlock_exclusive (left_node); 720 1.1 mrg return right_node; 721 1.1 mrg } 722 1.1 mrg } 723 1.1 mrg 724 1.1 mrg // Insert an entry. 725 1.1 mrg static bool 726 1.1 mrg btree_insert (struct btree *t, uintptr_type base, uintptr_type size, 727 1.1 mrg struct object *ob) 728 1.1 mrg { 729 1.1 mrg // Sanity check. 730 1.1 mrg if (!size) 731 1.1 mrg return false; 732 1.1 mrg 733 1.1 mrg // Access the root. 734 1.1 mrg struct btree_node *iter, *parent = NULL; 735 1.1 mrg { 736 1.1 mrg version_lock_lock_exclusive (&(t->root_lock)); 737 1.1 mrg iter = t->root; 738 1.1 mrg if (iter) 739 1.1 mrg { 740 1.1 mrg btree_node_lock_exclusive (iter); 741 1.1 mrg } 742 1.1 mrg else 743 1.1 mrg { 744 1.1 mrg t->root = iter = btree_allocate_node (t, false); 745 1.1 mrg } 746 1.1 mrg version_lock_unlock_exclusive (&(t->root_lock)); 747 1.1 mrg } 748 1.1 mrg 749 1.1 mrg // Walk down the btree with classic lock coupling and eager splits. 750 1.1 mrg // Strictly speaking this is not performance optimal, we could use 751 1.1 mrg // optimistic lock coupling until we hit a node that has to be modified. 752 1.1 mrg // But that is more difficult to implement and frame registration is 753 1.1 mrg // rare anyway, we use simple locking for now. 754 1.1 mrg 755 1.1 mrg uintptr_type fence = max_separator; 756 1.1 mrg while (btree_node_is_inner (iter)) 757 1.1 mrg { 758 1.1 mrg // Use eager splits to avoid lock coupling up. 759 1.1 mrg if (iter->entry_count == max_fanout_inner) 760 1.1 mrg btree_split_inner (t, &iter, &parent, base, size); 761 1.1 mrg 762 1.1 mrg unsigned slot = btree_node_find_inner_slot (iter, base); 763 1.1 mrg if (parent) 764 1.1 mrg btree_node_unlock_exclusive (parent); 765 1.1 mrg parent = iter; 766 1.1 mrg fence = iter->content.children[slot].separator; 767 1.1 mrg if (fence < base + size - 1) 768 1.1 mrg // The separator was set to the base - 1 of the leftmost leaf child 769 1.1 mrg // at some point but such an entry could have been removed afterwards. 770 1.1 mrg // As both insertion and removal are just walking down the tree with 771 1.1 mrg // only a few current nodes locked at a time, updating the separator 772 1.1 mrg // on removal is not possible, especially because btree_remove does 773 1.1 mrg // not know the size until it reaches leaf node. We must ensure that 774 1.1 mrg // the separator is not in a middle of some entry though, as 775 1.1 mrg // btree_lookup can look up any address in the entry's range and if 776 1.1 mrg // the separator is in the middle, addresses below it or equal to it 777 1.1 mrg // would be found while addresses above it would result in failed 778 1.1 mrg // lookup. Update the separator now. Assumption that users 779 1.1 mrg // ensure no overlapping registered ranges, there should be no 780 1.1 mrg // current entry for any address in the range. See PR119151. 781 1.1 mrg fence = iter->content.children[slot].separator = base + size - 1; 782 1.1 mrg iter = iter->content.children[slot].child; 783 1.1 mrg btree_node_lock_exclusive (iter); 784 1.1 mrg } 785 1.1 mrg 786 1.1 mrg // Make sure we have space. 787 1.1 mrg if (iter->entry_count == max_fanout_leaf) 788 1.1 mrg btree_split_leaf (t, &iter, &parent, fence, base); 789 1.1 mrg if (parent) 790 1.1 mrg btree_node_unlock_exclusive (parent); 791 1.1 mrg 792 1.1 mrg // Insert in node. 793 1.1 mrg unsigned slot = btree_node_find_leaf_slot (iter, base); 794 1.1 mrg if ((slot < iter->entry_count) && (iter->content.entries[slot].base == base)) 795 1.1 mrg { 796 1.1 mrg // Duplicate entry, this should never happen. 797 1.1 mrg btree_node_unlock_exclusive (iter); 798 1.1 mrg return false; 799 1.1 mrg } 800 1.1 mrg for (unsigned index = iter->entry_count; index > slot; --index) 801 1.1 mrg iter->content.entries[index] = iter->content.entries[index - 1]; 802 1.1 mrg struct leaf_entry *e = &(iter->content.entries[slot]); 803 1.1 mrg e->base = base; 804 1.1 mrg e->size = size; 805 1.1 mrg e->ob = ob; 806 1.1 mrg iter->entry_count++; 807 1.1 mrg btree_node_unlock_exclusive (iter); 808 1.1 mrg return true; 809 1.1 mrg } 810 1.1 mrg 811 1.1 mrg // Remove an entry. 812 1.1 mrg static struct object * 813 1.1 mrg btree_remove (struct btree *t, uintptr_type base) 814 1.1 mrg { 815 1.1 mrg // Access the root. 816 1.1 mrg version_lock_lock_exclusive (&(t->root_lock)); 817 1.1 mrg struct btree_node *iter = t->root; 818 1.1 mrg if (iter) 819 1.1 mrg btree_node_lock_exclusive (iter); 820 1.1 mrg version_lock_unlock_exclusive (&(t->root_lock)); 821 1.1 mrg if (!iter) 822 1.1 mrg return NULL; 823 1.1 mrg 824 1.1 mrg // Same strategy as with insert, walk down with lock coupling and 825 1.1 mrg // merge eagerly. 826 1.1 mrg while (btree_node_is_inner (iter)) 827 1.1 mrg { 828 1.1 mrg unsigned slot = btree_node_find_inner_slot (iter, base); 829 1.1 mrg struct btree_node *next = iter->content.children[slot].child; 830 1.1 mrg btree_node_lock_exclusive (next); 831 1.1 mrg if (btree_node_needs_merge (next)) 832 1.1 mrg { 833 1.1 mrg // Use eager merges to avoid lock coupling up. 834 1.1 mrg iter = btree_merge_node (t, slot, iter, base); 835 1.1 mrg } 836 1.1 mrg else 837 1.1 mrg { 838 1.1 mrg btree_node_unlock_exclusive (iter); 839 1.1 mrg iter = next; 840 1.1 mrg } 841 1.1 mrg } 842 1.1 mrg 843 1.1 mrg // Remove existing entry. 844 1.1 mrg unsigned slot = btree_node_find_leaf_slot (iter, base); 845 1.1 mrg if ((slot >= iter->entry_count) || (iter->content.entries[slot].base != base)) 846 1.1 mrg { 847 1.1 mrg // Not found, this should never happen. 848 1.1 mrg btree_node_unlock_exclusive (iter); 849 1.1 mrg return NULL; 850 1.1 mrg } 851 1.1 mrg struct object *ob = iter->content.entries[slot].ob; 852 1.1 mrg for (unsigned index = slot; index + 1 < iter->entry_count; ++index) 853 1.1 mrg iter->content.entries[index] = iter->content.entries[index + 1]; 854 1.1 mrg iter->entry_count--; 855 1.1 mrg btree_node_unlock_exclusive (iter); 856 1.1 mrg return ob; 857 1.1 mrg } 858 1.1 mrg 859 1.1 mrg // Find the corresponding entry for the given address. 860 1.1 mrg static struct object * 861 1.1 mrg btree_lookup (const struct btree *t, uintptr_type target_addr) 862 1.1 mrg { 863 1.1 mrg // Within this function many loads are relaxed atomic loads. 864 1.1 mrg // Use a macro to keep the code reasonable. 865 1.1 mrg #define RLOAD(x) __atomic_load_n (&(x), __ATOMIC_RELAXED) 866 1.1 mrg 867 1.1 mrg // For targets where unwind info is usually not registered through these 868 1.1 mrg // APIs anymore, avoid any sequential consistent atomics. 869 1.1 mrg // Use relaxed MO here, it is up to the app to ensure that the library 870 1.1 mrg // loading/initialization happens-before using that library in other 871 1.1 mrg // threads (in particular unwinding with that library's functions 872 1.1 mrg // appearing in the backtraces). Calling that library's functions 873 1.1 mrg // without waiting for the library to initialize would be racy. 874 1.1 mrg if (__builtin_expect (!RLOAD (t->root), 1)) 875 1.1 mrg return NULL; 876 1.1 mrg 877 1.1 mrg // The unwinding tables are mostly static, they only change when 878 1.1 mrg // frames are added or removed. This makes it extremely unlikely that they 879 1.1 mrg // change during a given unwinding sequence. Thus, we optimize for the 880 1.1 mrg // contention free case and use optimistic lock coupling. This does not 881 1.1 mrg // require any writes to shared state, instead we validate every read. It is 882 1.1 mrg // important that we do not trust any value that we have read until we call 883 1.1 mrg // validate again. Data can change at arbitrary points in time, thus we always 884 1.1 mrg // copy something into a local variable and validate again before acting on 885 1.1 mrg // the read. In the unlikely event that we encounter a concurrent change we 886 1.1 mrg // simply restart and try again. 887 1.1 mrg 888 1.1 mrg restart: 889 1.1 mrg struct btree_node *iter; 890 1.1 mrg uintptr_type lock; 891 1.1 mrg { 892 1.1 mrg // Accessing the root node requires defending against concurrent pointer 893 1.1 mrg // changes Thus we couple rootLock -> lock on root node -> validate rootLock 894 1.1 mrg if (!version_lock_lock_optimistic (&(t->root_lock), &lock)) 895 1.1 mrg goto restart; 896 1.1 mrg iter = RLOAD (t->root); 897 1.1 mrg if (!version_lock_validate (&(t->root_lock), lock)) 898 1.1 mrg goto restart; 899 1.1 mrg if (!iter) 900 1.1 mrg return NULL; 901 1.1 mrg uintptr_type child_lock; 902 1.1 mrg if ((!btree_node_lock_optimistic (iter, &child_lock)) 903 1.1 mrg || (!version_lock_validate (&(t->root_lock), lock))) 904 1.1 mrg goto restart; 905 1.1 mrg lock = child_lock; 906 1.1 mrg } 907 1.1 mrg 908 1.1 mrg // Now we can walk down towards the right leaf node. 909 1.1 mrg while (true) 910 1.1 mrg { 911 1.1 mrg enum node_type type = RLOAD (iter->type); 912 1.1 mrg unsigned entry_count = RLOAD (iter->entry_count); 913 1.1 mrg if (!btree_node_validate (iter, lock)) 914 1.1 mrg goto restart; 915 1.1 mrg if (!entry_count) 916 1.1 mrg return NULL; 917 1.1 mrg 918 1.1 mrg if (type == btree_node_inner) 919 1.1 mrg { 920 1.1 mrg // We cannot call find_inner_slot here because we need (relaxed) 921 1.1 mrg // atomic reads here. 922 1.1 mrg unsigned slot = 0; 923 1.1 mrg while ( 924 1.1 mrg ((slot + 1) < entry_count) 925 1.1 mrg && (RLOAD (iter->content.children[slot].separator) < target_addr)) 926 1.1 mrg ++slot; 927 1.1 mrg struct btree_node *child = RLOAD (iter->content.children[slot].child); 928 1.1 mrg if (!btree_node_validate (iter, lock)) 929 1.1 mrg goto restart; 930 1.1 mrg 931 1.1 mrg // The node content can change at any point in time, thus we must 932 1.1 mrg // interleave parent and child checks. 933 1.1 mrg uintptr_type child_lock; 934 1.1 mrg if (!btree_node_lock_optimistic (child, &child_lock)) 935 1.1 mrg goto restart; 936 1.1 mrg if (!btree_node_validate (iter, lock)) 937 1.1 mrg goto restart; // make sure we still point to the correct node after 938 1.1 mrg // acquiring the optimistic lock. 939 1.1 mrg 940 1.1 mrg // Go down 941 1.1 mrg iter = child; 942 1.1 mrg lock = child_lock; 943 1.1 mrg } 944 1.1 mrg else 945 1.1 mrg { 946 1.1 mrg // We cannot call find_leaf_slot here because we need (relaxed) 947 1.1 mrg // atomic reads here. 948 1.1 mrg unsigned slot = 0; 949 1.1 mrg while (((slot + 1) < entry_count) 950 1.1 mrg && (RLOAD (iter->content.entries[slot].base) 951 1.1 mrg + RLOAD (iter->content.entries[slot].size) 952 1.1 mrg <= target_addr)) 953 1.1 mrg ++slot; 954 1.1 mrg struct leaf_entry entry; 955 1.1 mrg entry.base = RLOAD (iter->content.entries[slot].base); 956 1.1 mrg entry.size = RLOAD (iter->content.entries[slot].size); 957 1.1 mrg entry.ob = RLOAD (iter->content.entries[slot].ob); 958 1.1 mrg if (!btree_node_validate (iter, lock)) 959 1.1 mrg goto restart; 960 1.1 mrg 961 1.1 mrg // Check if we have a hit. 962 1.1 mrg if ((entry.base <= target_addr) 963 1.1 mrg && (target_addr < entry.base + entry.size)) 964 1.1 mrg { 965 1.1 mrg return entry.ob; 966 1.1 mrg } 967 1.1 mrg return NULL; 968 1.1 mrg } 969 1.1 mrg } 970 1.1 mrg #undef RLOAD 971 1.1 mrg } 972 1.1 mrg 973 1.1 mrg #endif /* unwind-dw2-btree.h */ 974