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