4 * Userspace RCU library - Red-Black Tree
6 * Copyright (c) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * Implementation of RCU-adapted data structures and operations based on the RB
23 * tree algorithms found in chapter 12 of:
25 * Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and
26 * Clifford Stein. Introduction to Algorithms, Third Edition. The MIT
27 * Press, September 2009.
39 #include <urcu/rcurbtree.h>
40 #include <urcu-pointer.h>
41 #include <urcu-call-rcu.h>
42 #include <urcu/compiler.h>
45 #define dbg_printf(args...) printf(args)
47 #define dbg_printf(args...)
51 * Undefine this to enable the non-RCU rotate and transplant functions
54 #define RBTREE_RCU_SUPPORT_ROTATE_LEFT
55 #define RBTREE_RCU_SUPPORT_ROTATE_RIGHT
56 #define RBTREE_RCU_SUPPORT_TRANSPLANT
59 static pthread_mutex_t test_mutex
= PTHREAD_MUTEX_INITIALIZER
;
60 static pthread_mutex_t outer_mutex
= PTHREAD_MUTEX_INITIALIZER
;
63 void lock_outer_mutex(void)
65 pthread_mutex_lock(&outer_mutex
);
69 void unlock_outer_mutex(void)
71 pthread_mutex_unlock(&outer_mutex
);
75 void lock_test_mutex(void)
77 pthread_mutex_lock(&test_mutex
);
81 void unlock_test_mutex(void)
83 pthread_mutex_unlock(&test_mutex
);
88 void set_parent(struct rcu_rbtree_node
*node
,
89 struct rcu_rbtree_node
*parent
,
92 _CMM_STORE_SHARED(node
->parent
, ((unsigned long) parent
) | pos
);
96 struct rcu_rbtree_node
*get_parent(struct rcu_rbtree_node
*node
)
98 return (struct rcu_rbtree_node
*) (node
->parent
& ~1UL);
102 unsigned int get_pos(struct rcu_rbtree_node
*node
)
104 return (unsigned int) (node
->parent
& 1UL);
108 struct rcu_rbtree_node
*get_parent_and_pos(struct rcu_rbtree_node
*node
,
111 unsigned long parent_pos
= rcu_dereference(node
->parent
);
113 *pos
= (unsigned int) (parent_pos
& 1UL);
114 return (struct rcu_rbtree_node
*) (parent_pos
& ~1UL);
118 void set_decay(struct rcu_rbtree_node
*x
, struct rcu_rbtree_node
*xc
)
124 struct rcu_rbtree_node
*get_decay(struct rcu_rbtree_node
*x
)
128 while (x
->decay_next
)
134 struct rcu_rbtree_node
*is_decay(struct rcu_rbtree_node
*x
)
136 return x
->decay_next
;
140 struct rcu_rbtree_node
*dup_decay_node(struct rcu_rbtree
*rbtree
,
141 struct rcu_rbtree_node
*x
)
143 struct rcu_rbtree_node
*xc
;
145 if (rcu_rbtree_is_nil(x
))
148 xc
= rbtree
->rballoc();
149 memcpy(xc
, x
, sizeof(struct rcu_rbtree_node
));
150 xc
->decay_next
= NULL
;
152 call_rcu(&x
->head
, rbtree
->rbfree
);
157 * Info for range lookups:
158 * Range lookup information is only valid when used when searching for
159 * ranges. It should never be used in next/prev traversal because the
160 * pointers to parents are not in sync with the parent vision of the
164 void _set_left_dup_decay(struct rcu_rbtree
*rbtree
,
165 struct rcu_rbtree_node
*node
,
166 struct rcu_rbtree_node
*left
,
167 struct rcu_rbtree_node
**top
,
168 struct rcu_rbtree_node
**top_child
,
169 unsigned int *top_child_pos
, int copy
)
171 struct rcu_rbtree_node
*first_node
= node
; /* already a copy */
177 if (rcu_rbtree_is_nil(left
)) {
178 min_child_key
= node
->key
;
180 min_child_key
= left
->min_child_key
;
181 assert(rbtree
->comp(left
->key
, left
->min_child_key
) >= 0);
182 assert(rbtree
->comp(node
->key
, left
->min_child_key
) >= 0);
184 if (min_child_key
!= node
->min_child_key
) {
185 if (node
!= first_node
) {
187 node
= dup_decay_node(rbtree
, node
);
189 set_parent(left
, node
, IS_LEFT
);
192 node
->min_child_key
= min_child_key
;
194 if (node
!= first_node
) {
200 *top_child_pos
= get_pos(left
);
203 *top
= get_parent(node
);
207 *top_child_pos
= get_pos(node
);
212 } while (get_pos(node
) == IS_LEFT
213 && !rcu_rbtree_is_nil(node
= get_parent(node
)));
215 if (rcu_rbtree_is_nil(node
)) {
221 *top_child_pos
= IS_LEFT
; /* arbitrary */
223 assert(get_pos(node
) == IS_RIGHT
);
225 *top
= get_parent(node
);
229 *top_child_pos
= IS_RIGHT
;
234 void set_left_dup_decay(struct rcu_rbtree
*rbtree
,
235 struct rcu_rbtree_node
*node
,
236 struct rcu_rbtree_node
*left
,
237 struct rcu_rbtree_node
**top
,
238 struct rcu_rbtree_node
**top_child
,
239 unsigned int *top_child_pos
)
241 _set_left_dup_decay(rbtree
, node
, left
, top
, top_child
,
246 void set_left_update_decay(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
,
247 struct rcu_rbtree_node
*left
)
249 struct rcu_rbtree_node
*first_node
= node
; /* already a copy */
252 if (node
!= first_node
) {
253 set_parent(node
->_right
,
254 get_decay(get_parent(node
->_right
)), IS_RIGHT
);
256 } while (get_pos(node
) == IS_LEFT
257 && !rcu_rbtree_is_nil(node
= get_parent(node
)));
261 void set_right_dup_decay(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
,
262 struct rcu_rbtree_node
*right
,
263 struct rcu_rbtree_node
**top
,
264 struct rcu_rbtree_node
**top_child
,
265 unsigned int *top_child_pos
)
267 struct rcu_rbtree_node
*first_node
= node
; /* already a copy */
269 node
->_right
= right
;
273 if (rcu_rbtree_is_nil(right
)) {
274 max_child_key
= node
->key
;
276 max_child_key
= right
->max_child_key
;
277 assert(rbtree
->comp(right
->key
, right
->max_child_key
) <= 0);
278 assert(rbtree
->comp(node
->key
, right
->max_child_key
) <= 0);
280 if (max_child_key
!= node
->max_child_key
) {
281 if (node
!= first_node
) {
282 node
= dup_decay_node(rbtree
, node
);
283 node
->_right
= right
;
284 set_parent(right
, node
, IS_RIGHT
);
286 node
->max_child_key
= max_child_key
;
288 if (node
!= first_node
) {
294 *top_child_pos
= get_pos(right
);
297 *top
= get_parent(node
);
301 *top_child_pos
= get_pos(node
);
306 } while (get_pos(node
) == IS_RIGHT
307 && !rcu_rbtree_is_nil(node
= get_parent(node
)));
309 if (rcu_rbtree_is_nil(node
)) {
315 *top_child_pos
= IS_RIGHT
; /* arbitrary */
317 assert(get_pos(node
) == IS_LEFT
);
319 *top
= get_parent(node
);
323 *top_child_pos
= IS_LEFT
;
328 void set_right_update_decay(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
,
329 struct rcu_rbtree_node
*right
)
331 struct rcu_rbtree_node
*first_node
= node
; /* already a copy */
334 if (node
!= first_node
) {
335 set_parent(node
->_left
,
336 get_decay(get_parent(node
->_left
)), IS_LEFT
);
338 } while (get_pos(node
) == IS_RIGHT
339 && !rcu_rbtree_is_nil(node
= get_parent(node
)));
344 * Deal with memory allocation errors.
345 * Can be ensured by reserving a pool of memory entries before doing the
346 * insertion, which will have to be function of number of
347 * transplantations/rotations required for the operation.
352 void show_tree(struct rcu_rbtree
*rbtree
)
354 struct rcu_rbtree_node
*node
;
356 node
= rcu_rbtree_min(rbtree
, rbtree
->root
);
357 while (!rcu_rbtree_is_nil(node
)) {
358 assert(!is_decay(node
));
359 printf("{ 0x%lX p:%lX r:%lX l:%lX %s %s %s} ",
360 (unsigned long)node
->key
,
361 (unsigned long) get_parent(node
)->key
,
362 (unsigned long) node
->_right
->key
,
363 (unsigned long) node
->_left
->key
,
364 node
->color
? "red" : "black",
365 get_pos(node
) ? "right" : "left",
366 node
->nil
? "nil" : "");
367 node
= rcu_rbtree_next(rbtree
, node
);
373 void show_tree(struct rcu_rbtree
*rbtree
)
379 struct rcu_rbtree_node
*make_nil(struct rcu_rbtree
*rbtree
)
381 return &rbtree
->nil_node
;
385 * Iterative rbtree search.
387 struct rcu_rbtree_node
*rcu_rbtree_search(struct rcu_rbtree
*rbtree
,
388 struct rcu_rbtree_node
*x
,
391 x
= rcu_dereference(x
);
394 while (!rcu_rbtree_is_nil(x
) && (comp
= rbtree
->comp(k
, x
->key
)) != 0) {
397 x
= rcu_dereference(x
->_left
);
399 x
= rcu_dereference(x
->_right
);
404 struct rcu_rbtree_node
*rcu_rbtree_search_min(struct rcu_rbtree
*rbtree
,
405 struct rcu_rbtree_node
*x
,
406 void *range_low
, void *range_high
)
408 struct rcu_rbtree_node
*xl
;
409 x
= rcu_dereference(x
);
411 dbg_printf("start search min x %lx low %lx high %lx\n",
412 (unsigned long) x
->key
,
413 (unsigned long) range_low
, (unsigned long) range_high
);
414 while (!rcu_rbtree_is_nil(x
)) {
416 xl
= rcu_dereference(x
->_left
);
417 dbg_printf("search min x %lx\n", (unsigned long) x
->key
);
418 dbg_printf("search min xl %lx\n", (unsigned long) xl
->key
);
419 if (!rcu_rbtree_is_nil(xl
)
420 && (rbtree
->comp(xl
->max_child_key
, range_low
) >= 0
421 || rbtree
->comp(xl
->key
, range_low
) == 0)) {
422 dbg_printf("go left\n");
424 } else if (rbtree
->comp(x
->key
, range_low
) >= 0
425 && rbtree
->comp(x
->key
, range_high
) <= 0) {
426 dbg_printf("got it!\n");
428 } else if (rbtree
->comp(range_low
, x
->min_child_key
) >= 0) {
429 dbg_printf("go right\n");
430 x
= rcu_dereference(x
->_right
);
432 dbg_printf("not found!\n");
433 x
= make_nil(rbtree
);
439 struct rcu_rbtree_node
*rcu_rbtree_search_max(struct rcu_rbtree
*rbtree
,
440 struct rcu_rbtree_node
*x
,
441 void *range_low
, void *range_high
)
443 struct rcu_rbtree_node
*xr
;
444 x
= rcu_dereference(x
);
446 dbg_printf("start search max x %lx low %lx high %lx\n",
447 (unsigned long) x
->key
,
448 (unsigned long) range_low
, (unsigned long) range_high
);
449 while (!rcu_rbtree_is_nil(x
)) {
451 xr
= rcu_dereference(x
->_right
);
452 dbg_printf("search max x %lx\n", (unsigned long) x
->key
);
453 dbg_printf("search max xl %lx\n", (unsigned long) xr
->key
);
454 if (!rcu_rbtree_is_nil(xr
)
455 && (rbtree
->comp(xr
->min_child_key
, range_high
) <= 0
456 || rbtree
->comp(xr
->key
, range_high
) == 0)) {
457 dbg_printf("go right\n");
459 } else if (rbtree
->comp(x
->key
, range_low
) >= 0
460 && rbtree
->comp(x
->key
, range_high
) <= 0) {
461 dbg_printf("got it!\n");
463 } else if (rbtree
->comp(range_high
, x
->max_child_key
) <= 0) {
464 dbg_printf("go left\n");
465 x
= rcu_dereference(x
->_left
);
467 dbg_printf("not found!\n");
468 x
= make_nil(rbtree
);
475 struct rcu_rbtree_node
*rcu_rbtree_min_dup_decay(struct rcu_rbtree
*rbtree
,
476 struct rcu_rbtree_node
*x
,
477 struct rcu_rbtree_node
**zr
)
479 struct rcu_rbtree_node
*xl
;
481 x
= rcu_dereference(x
);
483 if (rcu_rbtree_is_nil(x
)) {
487 *zr
= x
= dup_decay_node(rbtree
, x
);
489 while (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->_left
))) {
490 x
= dup_decay_node(rbtree
, xl
);
491 set_parent(x
, get_decay(get_parent(x
)), get_pos(x
));
492 get_parent(x
)->_left
= get_decay(get_parent(x
)->_left
);
498 struct rcu_rbtree_node
*rcu_rbtree_min_update_decay(struct rcu_rbtree
*rbtree
,
499 struct rcu_rbtree_node
*x
)
501 struct rcu_rbtree_node
*xl
;
503 x
= rcu_dereference(x
);
505 if (rcu_rbtree_is_nil(x
))
508 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
510 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
514 while (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->_left
))) {
516 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
518 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
524 struct rcu_rbtree_node
*rcu_rbtree_min(struct rcu_rbtree
*rbtree
,
525 struct rcu_rbtree_node
*x
)
527 struct rcu_rbtree_node
*xl
;
529 x
= rcu_dereference(x
);
531 if (rcu_rbtree_is_nil(x
))
534 while (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->_left
)))
539 struct rcu_rbtree_node
*rcu_rbtree_max(struct rcu_rbtree
*rbtree
,
540 struct rcu_rbtree_node
*x
)
542 struct rcu_rbtree_node
*xr
;
544 x
= rcu_dereference(x
);
546 if (rcu_rbtree_is_nil(x
))
549 while (!rcu_rbtree_is_nil(xr
= rcu_dereference(x
->_right
)))
556 * Updates should wait for a grace period between update of the
557 * redirect pointer and update of the parent child pointer. This is to make sure
558 * that no reference to the old entry exist.
562 * RCU read lock must be held across the next/prev calls to ensure validity of
565 struct rcu_rbtree_node
*rcu_rbtree_next(struct rcu_rbtree
*rbtree
,
566 struct rcu_rbtree_node
*x
)
568 struct rcu_rbtree_node
*xr
, *y
;
571 x
= rcu_dereference(x
);
573 if (!rcu_rbtree_is_nil(xr
= rcu_dereference(x
->_right
)))
574 return rcu_rbtree_min(rbtree
, xr
);
575 y
= get_parent_and_pos(x
, &x_pos
);
576 while (!rcu_rbtree_is_nil(y
) && x_pos
== IS_RIGHT
) {
578 y
= get_parent_and_pos(y
, &x_pos
);
583 struct rcu_rbtree_node
*rcu_rbtree_prev(struct rcu_rbtree
*rbtree
,
584 struct rcu_rbtree_node
*x
)
586 struct rcu_rbtree_node
*xl
, *y
;
589 x
= rcu_dereference(x
);
591 if (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->_left
)))
592 return rcu_rbtree_max(rbtree
, xl
);
593 y
= get_parent_and_pos(x
, &x_pos
);
594 while (!rcu_rbtree_is_nil(y
) && x_pos
== IS_LEFT
) {
596 y
= get_parent_and_pos(y
, &x_pos
);
602 * We have to ensure these assumptions are correct for prev/next
605 * with x being a right child, the assumption that:
606 * get_parent(x)->_right == x
607 * or if x is a left child, the assumption that:
608 * get_parent(x)->_left == x
610 * This explains why we have to allocate a vc copy of the node for left_rotate,
611 * right_rotate and transplant operations.
613 * We always ensure that the right/left child and correct parent is set in the
614 * node copies *before* we reparent the children and make the upper-level point
618 /* RCU: copy x and y, atomically point to new versions. GC old. */
619 /* Should be eventually followed by a cmm_smp_wmc() */
621 #ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
624 void left_rotate(struct rcu_rbtree
*rbtree
,
625 struct rcu_rbtree_node
*x
)
627 struct rcu_rbtree_node
*y
, *y_left
, *top
, *top_child
;
628 unsigned int top_child_pos
;
633 /* Now operate on new copy, decay old versions */
634 x
= dup_decay_node(rbtree
, x
);
635 y
= dup_decay_node(rbtree
, y
);
636 y_left
= dup_decay_node(rbtree
, y_left
);
638 /* Internal node modifications */
639 set_parent(y
, get_parent(x
), get_pos(x
));
640 set_parent(x
, y
, IS_LEFT
);
641 set_left_dup_decay(rbtree
, y
, x
, &top
, &top_child
, &top_child_pos
);
642 set_right_dup_decay(rbtree
, x
, y_left
, NULL
, NULL
, NULL
);
643 assert(!is_decay(top
));
644 assert(!is_decay(top_child
));
646 if (!rcu_rbtree_is_nil(y_left
))
647 set_parent(y_left
, x
, IS_RIGHT
);
649 cmm_smp_wmb(); /* write into node before publish */
651 /* External references update (visible by readers) */
652 if (rcu_rbtree_is_nil(top
))
653 _CMM_STORE_SHARED(rbtree
->root
, top_child
);
654 else if (top_child_pos
== IS_LEFT
)
655 _CMM_STORE_SHARED(top
->_left
, top_child
);
657 _CMM_STORE_SHARED(top
->_right
, top_child
);
659 /* Point children to new copy (parent only used by updates/next/prev) */
660 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
662 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)),
664 if (!rcu_rbtree_is_nil(y_left
)) {
665 set_parent(y_left
->_right
,
666 get_decay(get_parent(y_left
->_right
)),
667 get_pos(y_left
->_right
));
668 set_parent(y_left
->_left
,
669 get_decay(get_parent(y_left
->_left
)),
670 get_pos(y_left
->_left
));
672 set_left_update_decay(rbtree
, y
, x
);
675 assert(y
== rbtree
->root
|| get_parent(y
)->_left
== y
676 || get_parent(y
)->_right
== y
);
677 assert(x
== rbtree
->root
|| get_parent(x
)->_left
== x
678 || get_parent(x
)->_right
== x
);
679 assert(rcu_rbtree_is_nil(x
->_right
) || get_parent(x
->_right
) == x
);
680 assert(rcu_rbtree_is_nil(x
->_left
) || get_parent(x
->_left
) == x
);
681 assert(rcu_rbtree_is_nil(y
->_right
) || get_parent(y
->_right
) == y
);
682 assert(rcu_rbtree_is_nil(y
->_left
) || get_parent(y
->_left
) == y
);
683 assert(!is_decay(rbtree
->root
));
684 assert(!is_decay(x
));
685 assert(!is_decay(y
));
686 assert(!is_decay(x
->_right
));
687 assert(!is_decay(x
->_left
));
688 assert(!is_decay(y
->_right
));
689 assert(!is_decay(y
->_left
));
694 /* non-rcu version */
696 void left_rotate(struct rcu_rbtree
*rbtree
,
697 struct rcu_rbtree_node
*x
)
699 struct rcu_rbtree_node
*y
;
703 x
->_right
= y
->_left
;
704 if (!rcu_rbtree_is_nil(y
->_left
))
705 set_parent(y
->_left
, x
, IS_RIGHT
);
706 set_parent(y
, get_parent(x
), get_pos(x
));
707 if (rcu_rbtree_is_nil(get_parent(x
)))
709 else if (x
== get_parent(x
)->_left
) {
710 get_parent(x
)->_left
= y
;
712 get_parent(x
)->_right
= y
;
715 set_parent(x
, y
, IS_LEFT
);
721 #ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
723 void right_rotate(struct rcu_rbtree
*rbtree
,
724 struct rcu_rbtree_node
*x
)
726 struct rcu_rbtree_node
*y
, *y_right
, *top
, *top_child
;
727 unsigned int top_child_pos
;
732 /* Now operate on new copy, decay old versions */
733 x
= dup_decay_node(rbtree
, x
);
734 y
= dup_decay_node(rbtree
, y
);
735 y_right
= dup_decay_node(rbtree
, y_right
);
737 /* Internal node modifications */
738 set_parent(y
, get_parent(x
), get_pos(x
));
739 set_parent(x
, y
, IS_RIGHT
);
740 set_right_dup_decay(rbtree
, y
, x
, &top
, &top_child
, &top_child_pos
);
741 set_left_dup_decay(rbtree
, x
, y_right
, NULL
, NULL
, NULL
);
742 assert(!is_decay(top
));
743 assert(!is_decay(top_child
));
745 if (!rcu_rbtree_is_nil(y_right
))
746 set_parent(y_right
, x
, IS_LEFT
);
748 cmm_smp_wmb(); /* write into node before publish */
750 /* External references update (visible by readers) */
751 if (rcu_rbtree_is_nil(top
))
752 _CMM_STORE_SHARED(rbtree
->root
, top_child
);
753 else if (top_child_pos
== IS_RIGHT
)
754 _CMM_STORE_SHARED(top
->_right
, top_child
);
756 _CMM_STORE_SHARED(top
->_left
, top_child
);
758 /* Point children to new copy (parent only used by updates/next/prev) */
759 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
761 set_parent(y
->_left
, get_decay(get_parent(y
->_left
)),
763 if (!rcu_rbtree_is_nil(y_right
)) {
764 set_parent(y_right
->_left
,
765 get_decay(get_parent(y_right
->_left
)),
766 get_pos(y_right
->_left
));
767 set_parent(y_right
->_right
,
768 get_decay(get_parent(y_right
->_right
)),
769 get_pos(y_right
->_right
));
771 set_right_update_decay(rbtree
, y
, x
);
775 assert(y
== rbtree
->root
|| get_parent(y
)->_right
== y
776 || get_parent(y
)->_left
== y
);
777 assert(x
== rbtree
->root
|| get_parent(x
)->_right
== x
778 || get_parent(x
)->_left
== x
);
779 assert(rcu_rbtree_is_nil(x
->_left
) || get_parent(x
->_left
) == x
);
780 assert(rcu_rbtree_is_nil(x
->_right
) || get_parent(x
->_right
) == x
);
781 assert(rcu_rbtree_is_nil(y
->_left
) || get_parent(y
->_left
) == y
);
782 assert(rcu_rbtree_is_nil(y
->_right
) || get_parent(y
->_right
) == y
);
783 assert(!is_decay(rbtree
->root
));
784 assert(!is_decay(x
));
785 assert(!is_decay(y
));
786 assert(!is_decay(x
->_left
));
787 assert(!is_decay(x
->_right
));
788 assert(!is_decay(y
->_left
));
789 assert(!is_decay(y
->_right
));
794 /* non-rcu version */
796 void right_rotate(struct rcu_rbtree
*rbtree
,
797 struct rcu_rbtree_node
*x
)
799 struct rcu_rbtree_node
*y
;
803 x
->_left
= y
->_right
;
804 if (!rcu_rbtree_is_nil(y
->_right
))
805 set_parent(y
->_right
, x
, IS_LEFT
);
806 set_parent(y
, get_parent(x
), get_pos(x
));
807 if (rcu_rbtree_is_nil(get_parent(x
)))
809 else if (x
== get_parent(x
)->_right
) {
810 get_parent(x
)->_right
= y
;
812 get_parent(x
)->_left
= y
;
815 set_parent(x
, y
, IS_RIGHT
);
821 static void rcu_rbtree_insert_fixup(struct rcu_rbtree
*rbtree
,
822 struct rcu_rbtree_node
*z
)
824 struct rcu_rbtree_node
*y
;
826 dbg_printf("insert fixup %p\n", z
->key
);
827 assert(!is_decay(rbtree
->root
));
829 while (get_parent(z
)->color
== COLOR_RED
) {
830 if (get_parent(z
) == get_parent(get_parent(z
))->_left
) {
831 y
= get_parent(get_parent(z
))->_right
;
832 if (y
->color
== COLOR_RED
) {
833 get_parent(z
)->color
= COLOR_BLACK
;
834 y
->color
= COLOR_BLACK
;
835 get_parent(get_parent(z
))->color
= COLOR_RED
;
836 z
= get_parent(get_parent(z
));
838 if (z
== get_parent(z
)->_right
) {
840 left_rotate(rbtree
, z
);
842 assert(!is_decay(rbtree
->root
));
844 get_parent(z
)->color
= COLOR_BLACK
;
845 get_parent(get_parent(z
))->color
= COLOR_RED
;
846 assert(!is_decay(z
));
847 assert(!is_decay(get_parent(z
)));
848 assert(!is_decay(get_parent(get_parent(z
))));
849 right_rotate(rbtree
, get_parent(get_parent(z
)));
850 assert(!is_decay(z
));
851 assert(!is_decay(rbtree
->root
));
854 y
= get_parent(get_parent(z
))->_left
;
855 if (y
->color
== COLOR_RED
) {
856 get_parent(z
)->color
= COLOR_BLACK
;
857 y
->color
= COLOR_BLACK
;
858 get_parent(get_parent(z
))->color
= COLOR_RED
;
859 z
= get_parent(get_parent(z
));
861 if (z
== get_parent(z
)->_left
) {
863 right_rotate(rbtree
, z
);
865 assert(!is_decay(rbtree
->root
));
867 get_parent(z
)->color
= COLOR_BLACK
;
868 get_parent(get_parent(z
))->color
= COLOR_RED
;
869 left_rotate(rbtree
, get_parent(get_parent(z
)));
870 assert(!is_decay(z
));
871 assert(!is_decay(rbtree
->root
));
875 rbtree
->root
->color
= COLOR_BLACK
;
879 * rcu_rbtree_insert - Insert a node in the RCU rbtree
881 * Returns 0 on success, or < 0 on error.
883 int rcu_rbtree_insert(struct rcu_rbtree
*rbtree
,
884 struct rcu_rbtree_node
*z
)
886 struct rcu_rbtree_node
*x
, *y
, *top
, *top_child
;
887 unsigned int top_child_pos
;
889 dbg_printf("insert %p\n", z
->key
);
890 assert(!is_decay(rbtree
->root
));
892 y
= make_nil(rbtree
);
894 while (!rcu_rbtree_is_nil(x
)) {
896 if (rbtree
->comp(z
->key
, x
->key
) < 0)
902 z
->_left
= make_nil(rbtree
);
903 z
->_right
= make_nil(rbtree
);
904 z
->min_child_key
= z
->key
;
905 z
->max_child_key
= z
->key
;
906 z
->color
= COLOR_RED
;
908 z
->decay_next
= NULL
;
910 if (rcu_rbtree_is_nil(y
))
911 set_parent(z
, y
, IS_RIGHT
); /* pos arbitrary for root node */
912 else if (rbtree
->comp(z
->key
, y
->key
) < 0)
913 set_parent(z
, y
, IS_LEFT
);
915 set_parent(z
, y
, IS_RIGHT
);
918 * Order stores to z (children/parents) before stores that will make it
919 * visible to the rest of the tree.
923 if (rcu_rbtree_is_nil(y
)) {
924 _CMM_STORE_SHARED(rbtree
->root
, z
);
925 } else if (rbtree
->comp(z
->key
, y
->key
) < 0) {
926 set_left_dup_decay(rbtree
, y
, z
, &top
, &top_child
,
928 if (rcu_rbtree_is_nil(top
))
929 _CMM_STORE_SHARED(rbtree
->root
, top_child
);
930 else if (top_child_pos
== IS_LEFT
)
931 _CMM_STORE_SHARED(top
->_left
, top_child
);
933 _CMM_STORE_SHARED(top
->_right
, top_child
);
934 set_left_update_decay(rbtree
, y
, z
);
936 set_right_dup_decay(rbtree
, y
, z
, &top
, &top_child
,
938 if (rcu_rbtree_is_nil(top
))
939 _CMM_STORE_SHARED(rbtree
->root
, top_child
);
940 else if (top_child_pos
== IS_LEFT
)
941 _CMM_STORE_SHARED(top
->_left
, top_child
);
943 _CMM_STORE_SHARED(top
->_right
, top_child
);
944 set_right_update_decay(rbtree
, y
, z
);
946 rcu_rbtree_insert_fixup(rbtree
, z
);
948 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
957 * Transplant v into u position.
960 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
963 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
964 struct rcu_rbtree_node
*u
,
965 struct rcu_rbtree_node
*v
,
966 unsigned int copy_parents
)
968 struct rcu_rbtree_node
*top
, *top_child
;
969 unsigned int top_child_pos
;
971 dbg_printf("transplant %p\n", v
->key
);
973 if (!rcu_rbtree_is_nil(v
))
974 v
= dup_decay_node(rbtree
, v
);
976 if (rcu_rbtree_is_nil(get_parent(u
))) {
977 /* pos is arbitrary for root node */
978 set_parent(v
, get_parent(u
), IS_RIGHT
);
979 cmm_smp_wmb(); /* write into node before publish */
980 _CMM_STORE_SHARED(rbtree
->root
, v
);
982 set_parent(v
, get_parent(u
), get_pos(u
));
983 cmm_smp_wmb(); /* write into node before publish */
985 if (get_pos(u
) == IS_LEFT
) {
986 _set_left_dup_decay(rbtree
, get_parent(u
), v
,
987 &top
, &top_child
, &top_child_pos
,
990 assert(copy_parents
);
991 set_right_dup_decay(rbtree
, get_parent(u
), v
,
992 &top
, &top_child
, &top_child_pos
);
995 if (rcu_rbtree_is_nil(top
))
996 _CMM_STORE_SHARED(rbtree
->root
, top_child
);
997 else if (top_child_pos
== IS_LEFT
)
998 _CMM_STORE_SHARED(top
->_left
, top_child
);
1000 _CMM_STORE_SHARED(top
->_right
, top_child
);
1002 /* Point children to new copy (parent only used by updates/next/prev) */
1003 if (get_pos(u
) == IS_LEFT
) {
1005 set_left_update_decay(rbtree
, get_parent(u
), v
);
1007 assert(copy_parents
);
1008 set_right_update_decay(rbtree
, get_parent(u
), v
);
1012 /* Point children to new copy (parent only used by updates/next/prev) */
1013 if (!rcu_rbtree_is_nil(v
)) {
1014 set_parent(v
->_right
, get_decay(get_parent(v
->_right
)),
1015 get_pos(v
->_right
));
1016 set_parent(v
->_left
, get_decay(get_parent(v
->_left
)),
1019 assert(!is_decay(rbtree
->root
));
1024 /* Non-RCU version */
1026 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
1027 struct rcu_rbtree_node
*u
,
1028 struct rcu_rbtree_node
*v
,
1029 unsigned int copy_parents
)
1031 dbg_printf("transplant %p\n", v
->key
);
1034 if (rcu_rbtree_is_nil(get_parent(u
)))
1036 else if (u
== get_parent(u
)->_left
)
1037 get_parent(u
)->_left
= v
;
1039 get_parent(u
)->_right
= v
;
1040 set_parent(v
, get_parent(u
), get_pos(u
));
1041 unlock_test_mutex();
1046 static void rcu_rbtree_remove_fixup(struct rcu_rbtree
*rbtree
,
1047 struct rcu_rbtree_node
*x
)
1049 dbg_printf("remove fixup %p\n", x
->key
);
1051 while (x
!= rbtree
->root
&& x
->color
== COLOR_BLACK
) {
1052 assert(!is_decay(get_parent(x
)));
1053 assert(!is_decay(get_parent(x
)->_left
));
1054 if (x
== get_parent(x
)->_left
) {
1055 struct rcu_rbtree_node
*w
;
1057 w
= get_parent(x
)->_right
;
1059 if (w
->color
== COLOR_RED
) {
1060 w
->color
= COLOR_BLACK
;
1061 get_parent(x
)->color
= COLOR_RED
;
1062 left_rotate(rbtree
, get_parent(x
));
1064 assert(!is_decay(rbtree
->root
));
1065 w
= get_parent(x
)->_right
;
1067 if (w
->_left
->color
== COLOR_BLACK
1068 && w
->_right
->color
== COLOR_BLACK
) {
1069 w
->color
= COLOR_RED
;
1071 assert(!is_decay(rbtree
->root
));
1072 assert(!is_decay(x
));
1074 if (w
->_right
->color
== COLOR_BLACK
) {
1075 w
->_left
->color
= COLOR_BLACK
;
1076 w
->color
= COLOR_RED
;
1077 right_rotate(rbtree
, w
);
1078 assert(!is_decay(rbtree
->root
));
1080 w
= get_parent(x
)->_right
;
1082 w
->color
= get_parent(x
)->color
;
1083 get_parent(x
)->color
= COLOR_BLACK
;
1084 w
->_right
->color
= COLOR_BLACK
;
1085 left_rotate(rbtree
, get_parent(x
));
1086 assert(!is_decay(rbtree
->root
));
1090 struct rcu_rbtree_node
*w
;
1092 w
= get_parent(x
)->_left
;
1094 if (w
->color
== COLOR_RED
) {
1095 w
->color
= COLOR_BLACK
;
1096 get_parent(x
)->color
= COLOR_RED
;
1097 right_rotate(rbtree
, get_parent(x
));
1098 assert(!is_decay(rbtree
->root
));
1100 w
= get_parent(x
)->_left
;
1102 if (w
->_right
->color
== COLOR_BLACK
1103 && w
->_left
->color
== COLOR_BLACK
) {
1104 w
->color
= COLOR_RED
;
1106 assert(!is_decay(rbtree
->root
));
1107 assert(!is_decay(x
));
1109 if (w
->_left
->color
== COLOR_BLACK
) {
1110 w
->_right
->color
= COLOR_BLACK
;
1111 w
->color
= COLOR_RED
;
1112 left_rotate(rbtree
, w
);
1113 assert(!is_decay(rbtree
->root
));
1115 w
= get_parent(x
)->_left
;
1117 w
->color
= get_parent(x
)->color
;
1118 get_parent(x
)->color
= COLOR_BLACK
;
1119 w
->_left
->color
= COLOR_BLACK
;
1120 right_rotate(rbtree
, get_parent(x
));
1121 assert(!is_decay(rbtree
->root
));
1126 x
->color
= COLOR_BLACK
;
1130 * Delete z. All non-copied children left/right positions are unchanged.
1133 void rcu_rbtree_remove_nonil(struct rcu_rbtree
*rbtree
,
1134 struct rcu_rbtree_node
*z
,
1135 struct rcu_rbtree_node
*y
)
1137 struct rcu_rbtree_node
*x
, *top
, *top_child
;
1138 unsigned int top_child_pos
;
1140 dbg_printf("remove nonil %p\n", z
->key
);
1143 assert(!is_decay(z
));
1144 assert(!is_decay(y
));
1145 assert(!is_decay(y
->_right
));
1146 assert(!is_decay(get_parent(y
)));
1148 assert(!is_decay(x
));
1149 if (get_parent(y
) == z
) {
1150 y
= dup_decay_node(rbtree
, y
);
1151 set_parent(x
, y
, get_pos(x
)); /* parent for nil */
1152 /* y is z's right node: set left will just update y */
1153 set_left_dup_decay(rbtree
, y
, z
->_left
,
1154 &top
, &top_child
, &top_child_pos
);
1155 assert(top_child
== y
);
1156 rcu_rbtree_transplant(rbtree
, z
, y
, 1);
1158 struct rcu_rbtree_node
*oy_right
, *z_right
;
1161 * Need to make sure y is always visible by readers.
1163 y
= rcu_rbtree_min_dup_decay(rbtree
, z
->_right
, &z_right
);
1164 assert(!is_decay(y
));
1165 assert(!is_decay(z
));
1166 oy_right
= y
->_right
;
1169 * The max child key of z_right does not change, because
1170 * we're only changing its left children.
1172 y
->_right
= z_right
;
1173 set_parent(y
->_right
, y
, IS_RIGHT
);
1174 if (rcu_rbtree_is_nil(y
->_right
))
1175 y
->max_child_key
= y
->key
;
1177 y
->max_child_key
= y
->_right
->max_child_key
;
1179 assert(!is_decay(z
->_left
));
1180 y
->_left
= z
->_left
;
1181 if (rcu_rbtree_is_nil(y
->_left
))
1182 y
->min_child_key
= y
->key
;
1184 y
->min_child_key
= y
->_left
->min_child_key
;
1186 assert(!is_decay(oy_right
));
1188 * Transplant of oy_right to old y's location will only
1189 * trigger a min/max update of the already copied branch
1190 * (which is not visible yet). We are transplanting
1191 * oy_right as a left child of old y's parent, so the
1192 * min values update propagated upward necessarily stops
1195 rcu_rbtree_transplant(rbtree
, y
, oy_right
, 0);
1196 rcu_rbtree_transplant(rbtree
, z
, y
, 1);
1197 /* Update children */
1198 (void) rcu_rbtree_min_update_decay(rbtree
, y
->_right
);
1201 assert(!is_decay(z
));
1202 assert(!is_decay(z
->_left
));
1203 y
->color
= z
->color
;
1204 set_parent(y
->_left
, y
, IS_LEFT
);
1205 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)), IS_RIGHT
);
1206 assert(!is_decay(y
->_left
));
1207 assert(!is_decay(y
->_right
));
1210 int rcu_rbtree_remove(struct rcu_rbtree
*rbtree
,
1211 struct rcu_rbtree_node
*z
)
1213 struct rcu_rbtree_node
*x
, *y
;
1214 unsigned int y_original_color
;
1216 assert(!is_decay(rbtree
->root
));
1217 dbg_printf("remove %p\n", z
->key
);
1220 assert(!is_decay(z
));
1222 y_original_color
= y
->color
;
1224 if (rcu_rbtree_is_nil(z
->_left
)) {
1225 rcu_rbtree_transplant(rbtree
, z
, z
->_right
, 1);
1226 assert(!is_decay(z
));
1227 x
= get_decay(z
->_right
);
1229 } else if (rcu_rbtree_is_nil(z
->_right
)) {
1230 rcu_rbtree_transplant(rbtree
, z
, z
->_left
, 1);
1231 assert(!is_decay(z
));
1232 x
= get_decay(z
->_left
);
1235 y
= rcu_rbtree_min(rbtree
, z
->_right
);
1236 assert(!is_decay(y
));
1237 y_original_color
= y
->color
;
1239 rcu_rbtree_remove_nonil(rbtree
, z
, y
);
1243 if (y_original_color
== COLOR_BLACK
)
1244 rcu_rbtree_remove_fixup(rbtree
, x
);
1247 * Commit all _CMM_STORE_SHARED().