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)
46 #define dbg_usleep(usecs) usleep(usecs)
48 #define dbg_printf(args...)
49 #define dbg_usleep(usecs)
53 * Undefine this to enable the non-RCU rotate and transplant functions
56 #define RBTREE_RCU_SUPPORT_ROTATE_LEFT
57 #define RBTREE_RCU_SUPPORT_ROTATE_RIGHT
58 #define RBTREE_RCU_SUPPORT_TRANSPLANT
61 static pthread_mutex_t test_mutex
= PTHREAD_MUTEX_INITIALIZER
;
62 static pthread_mutex_t outer_mutex
= PTHREAD_MUTEX_INITIALIZER
;
65 void lock_outer_mutex(void)
67 pthread_mutex_lock(&outer_mutex
);
71 void unlock_outer_mutex(void)
73 pthread_mutex_unlock(&outer_mutex
);
77 void lock_test_mutex(void)
79 pthread_mutex_lock(&test_mutex
);
83 void unlock_test_mutex(void)
85 pthread_mutex_unlock(&test_mutex
);
90 void set_parent(struct rcu_rbtree_node
*node
,
91 struct rcu_rbtree_node
*parent
,
94 _CMM_STORE_SHARED(node
->parent
, ((unsigned long) parent
) | pos
);
98 struct rcu_rbtree_node
*get_parent(struct rcu_rbtree_node
*node
)
100 return (struct rcu_rbtree_node
*) (node
->parent
& ~1UL);
104 unsigned int get_pos(struct rcu_rbtree_node
*node
)
106 return (unsigned int) (node
->parent
& 1UL);
110 struct rcu_rbtree_node
*get_parent_and_pos(struct rcu_rbtree_node
*node
,
113 unsigned long parent_pos
= rcu_dereference(node
->parent
);
115 *pos
= (unsigned int) (parent_pos
& 1UL);
116 return (struct rcu_rbtree_node
*) (parent_pos
& ~1UL);
120 void set_decay(struct rcu_rbtree_node
*x
, struct rcu_rbtree_node
*xc
)
126 struct rcu_rbtree_node
*get_decay(struct rcu_rbtree_node
*x
)
130 while (x
->decay_next
)
136 struct rcu_rbtree_node
*is_decay(struct rcu_rbtree_node
*x
)
138 return x
->decay_next
;
142 struct rcu_rbtree_node
*dup_decay_node(struct rcu_rbtree
*rbtree
,
143 struct rcu_rbtree_node
*x
)
145 struct rcu_rbtree_node
*xc
;
147 if (rcu_rbtree_is_nil(rbtree
, x
))
150 xc
= rbtree
->rballoc();
151 memcpy(xc
, x
, sizeof(struct rcu_rbtree_node
));
152 xc
->decay_next
= NULL
;
154 call_rcu(&x
->head
, rbtree
->rbfree
);
159 * Info for range lookups:
160 * Range lookup information is only valid when used when searching for
161 * ranges. It should never be used in next/prev traversal because the
162 * pointers to parents are not in sync with the parent vision of the
166 void set_left(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
,
167 struct rcu_rbtree_node
*left
)
173 void set_right(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
,
174 struct rcu_rbtree_node
*right
)
176 node
->_right
= right
;
181 * Deal with memory allocation errors.
182 * Can be ensured by reserving a pool of memory entries before doing the
183 * insertion, which will have to be function of number of
184 * transplantations/rotations required for the operation.
189 void show_tree(struct rcu_rbtree
*rbtree
)
191 struct rcu_rbtree_node
*node
;
193 node
= rcu_rbtree_min(rbtree
, rbtree
->root
);
194 while (!rcu_rbtree_is_nil(rbtree
, node
)) {
195 assert(!is_decay(node
));
196 printf("{ b:%lX e:%lX pb: %lX r:%lX l:%lX %s %s %s} ",
197 (unsigned long) node
->begin
,
198 (unsigned long) node
->end
,
199 (unsigned long) get_parent(node
)->begin
,
200 (unsigned long) node
->_right
->begin
,
201 (unsigned long) node
->_left
->begin
,
202 node
->color
? "red" : "black",
203 get_pos(node
) ? "right" : "left",
204 rcu_rbtree_is_nil(rbtree
, node
) ? "nil" : "");
205 node
= rcu_rbtree_next(rbtree
, node
);
211 void show_tree(struct rcu_rbtree
*rbtree
)
217 struct rcu_rbtree_node
*make_nil(struct rcu_rbtree
*rbtree
)
219 return &rbtree
->nil_node
;
223 * Iterative rbtree search.
225 struct rcu_rbtree_node
*rcu_rbtree_search(struct rcu_rbtree
*rbtree
,
226 struct rcu_rbtree_node
*x
,
229 x
= rcu_dereference(x
);
232 while (!rcu_rbtree_is_nil(rbtree
, x
) && (comp
= rbtree
->comp(k
, x
->begin
)) != 0) {
235 x
= rcu_dereference(x
->_left
);
237 x
= rcu_dereference(x
->_right
);
243 struct rcu_rbtree_node
*rcu_rbtree_min_dup_decay(struct rcu_rbtree
*rbtree
,
244 struct rcu_rbtree_node
*x
,
245 struct rcu_rbtree_node
**zr
)
247 struct rcu_rbtree_node
*xl
;
249 x
= rcu_dereference(x
);
251 if (rcu_rbtree_is_nil(rbtree
, x
)) {
255 *zr
= x
= dup_decay_node(rbtree
, x
);
257 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
))) {
258 x
= dup_decay_node(rbtree
, xl
);
259 set_parent(x
, get_decay(get_parent(x
)), get_pos(x
));
260 get_parent(x
)->_left
= get_decay(get_parent(x
)->_left
);
266 struct rcu_rbtree_node
*rcu_rbtree_min_update_decay(struct rcu_rbtree
*rbtree
,
267 struct rcu_rbtree_node
*x
)
269 struct rcu_rbtree_node
*xl
;
271 x
= rcu_dereference(x
);
273 if (rcu_rbtree_is_nil(rbtree
, x
))
276 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
278 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
282 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
))) {
284 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
286 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
292 struct rcu_rbtree_node
*rcu_rbtree_min(struct rcu_rbtree
*rbtree
,
293 struct rcu_rbtree_node
*x
)
295 struct rcu_rbtree_node
*xl
;
297 x
= rcu_dereference(x
);
299 if (rcu_rbtree_is_nil(rbtree
, x
))
302 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
)))
307 struct rcu_rbtree_node
*rcu_rbtree_max(struct rcu_rbtree
*rbtree
,
308 struct rcu_rbtree_node
*x
)
310 struct rcu_rbtree_node
*xr
;
312 x
= rcu_dereference(x
);
314 if (rcu_rbtree_is_nil(rbtree
, x
))
317 while (!rcu_rbtree_is_nil(rbtree
, xr
= rcu_dereference(x
->_right
)))
324 * Updates should wait for a grace period between update of the
325 * redirect pointer and update of the parent child pointer. This is to make sure
326 * that no reference to the old entry exist.
330 * RCU read lock must be held across the next/prev calls to ensure validity of
333 struct rcu_rbtree_node
*rcu_rbtree_next(struct rcu_rbtree
*rbtree
,
334 struct rcu_rbtree_node
*x
)
336 struct rcu_rbtree_node
*xr
, *y
;
339 x
= rcu_dereference(x
);
341 if (!rcu_rbtree_is_nil(rbtree
, xr
= rcu_dereference(x
->_right
)))
342 return rcu_rbtree_min(rbtree
, xr
);
343 y
= get_parent_and_pos(x
, &x_pos
);
344 while (!rcu_rbtree_is_nil(rbtree
, y
) && x_pos
== IS_RIGHT
) {
346 y
= get_parent_and_pos(y
, &x_pos
);
351 struct rcu_rbtree_node
*rcu_rbtree_prev(struct rcu_rbtree
*rbtree
,
352 struct rcu_rbtree_node
*x
)
354 struct rcu_rbtree_node
*xl
, *y
;
357 x
= rcu_dereference(x
);
359 if (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
)))
360 return rcu_rbtree_max(rbtree
, xl
);
361 y
= get_parent_and_pos(x
, &x_pos
);
362 while (!rcu_rbtree_is_nil(rbtree
, y
) && x_pos
== IS_LEFT
) {
364 y
= get_parent_and_pos(y
, &x_pos
);
370 void *calculate_node_max_end(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
)
375 if (!rcu_rbtree_is_nil(rbtree
, node
->_right
)) {
376 if (rbtree
->comp(max_end
, node
->_right
->max_end
) < 0)
377 max_end
= node
->_right
->max_end
;
379 if (!rcu_rbtree_is_nil(rbtree
, node
->_left
)) {
380 if (rbtree
->comp(max_end
, node
->_left
->max_end
) < 0)
381 max_end
= node
->_left
->max_end
;
387 * "node" needs to be non-visible by readers.
390 void populate_node_end(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
,
391 unsigned int copy_parents
, struct rcu_rbtree_node
*stop
)
393 struct rcu_rbtree_node
*prev
= NULL
, *orig_node
= node
, *top
;
399 assert(!rcu_rbtree_is_nil(rbtree
, node
));
401 max_end
= calculate_node_max_end(rbtree
, node
);
402 if (rbtree
->comp(max_end
, node
->max_end
) != 0) {
403 if (prev
&& copy_parents
) {
404 node
= dup_decay_node(rbtree
, node
);
405 if (get_pos(prev
) == IS_RIGHT
)
409 set_parent(prev
, node
, get_pos(prev
));
411 node
->max_end
= max_end
;
414 * We did not have to change the current node,
415 * so set the pointer to the prev node. If prev
416 * was null, this means we are coming in the
417 * first loop, and must update the parent of the
418 * node received as parameter (node).
422 top
= get_parent(node
);
423 cmm_smp_wmb(); /* write into node before publish */
424 /* make new branch visible to readers */
425 if (rcu_rbtree_is_nil(rbtree
, top
))
426 _CMM_STORE_SHARED(rbtree
->root
, node
);
427 if (get_pos(node
) == IS_LEFT
)
428 _CMM_STORE_SHARED(top
->_left
, node
);
430 _CMM_STORE_SHARED(top
->_right
, node
);
434 /* Check for propagation stop */
439 node
= get_parent(node
);
440 } while (!rcu_rbtree_is_nil(rbtree
, node
));
442 top
= node
; /* nil */
443 cmm_smp_wmb(); /* write into node before publish */
444 /* make new branch visible to readers */
445 _CMM_STORE_SHARED(rbtree
->root
, prev
);
450 /* update children */
453 assert(!rcu_rbtree_is_nil(rbtree
, node
));
454 set_parent(node
->_left
, get_decay(get_parent(node
->_left
)), IS_LEFT
);
455 set_parent(node
->_right
, get_decay(get_parent(node
->_right
)), IS_RIGHT
);
456 } while ((node
= get_parent(node
)) != top
);
460 * We have to ensure these assumptions are correct for prev/next
463 * with x being a right child, the assumption that:
464 * get_parent(x)->_right == x
465 * or if x is a left child, the assumption that:
466 * get_parent(x)->_left == x
468 * This explains why we have to allocate a vc copy of the node for left_rotate,
469 * right_rotate and transplant operations.
471 * We always ensure that the right/left child and correct parent is set in the
472 * node copies *before* we reparent the children and make the upper-level point
476 /* RCU: copy x and y, atomically point to new versions. GC old. */
477 /* Should be eventually followed by a cmm_smp_wmc() */
479 #ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
482 void left_rotate(struct rcu_rbtree
*rbtree
,
483 struct rcu_rbtree_node
*x
)
485 struct rcu_rbtree_node
*y
, *y_left
;
490 /* Now operate on new copy, decay old versions */
491 x
= dup_decay_node(rbtree
, x
);
492 y
= dup_decay_node(rbtree
, y
);
493 y_left
= dup_decay_node(rbtree
, y_left
);
495 /* Internal node modifications */
496 set_parent(y
, get_parent(x
), get_pos(x
));
497 set_parent(x
, y
, IS_LEFT
);
498 set_left(rbtree
, y
, x
);
499 set_right(rbtree
, x
, y_left
);
501 if (!rcu_rbtree_is_nil(rbtree
, y_left
))
502 set_parent(y_left
, x
, IS_RIGHT
);
505 * We only changed the relative position of x and y wrt their
506 * children, and reparented y (but are keeping the same nodes in
507 * place, so its parent does not need to have end value
510 x
->max_end
= calculate_node_max_end(rbtree
, x
);
511 y
->max_end
= calculate_node_max_end(rbtree
, y
);
513 cmm_smp_wmb(); /* write into node before publish */
515 /* External references update (visible by readers) */
516 if (rcu_rbtree_is_nil(rbtree
, get_parent(y
)))
517 _CMM_STORE_SHARED(rbtree
->root
, y
);
518 else if (get_pos(y
) == IS_LEFT
)
519 _CMM_STORE_SHARED(get_parent(y
)->_left
, y
);
521 _CMM_STORE_SHARED(get_parent(y
)->_right
, y
);
523 /* Point children to new copy (parent only used by updates/next/prev) */
524 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
526 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)),
528 if (!rcu_rbtree_is_nil(rbtree
, y_left
)) {
529 set_parent(y_left
->_right
,
530 get_decay(get_parent(y_left
->_right
)),
531 get_pos(y_left
->_right
));
532 set_parent(y_left
->_left
,
533 get_decay(get_parent(y_left
->_left
)),
534 get_pos(y_left
->_left
));
538 assert(y
== rbtree
->root
|| get_parent(y
)->_left
== y
539 || get_parent(y
)->_right
== y
);
540 assert(x
== rbtree
->root
|| get_parent(x
)->_left
== x
541 || get_parent(x
)->_right
== x
);
542 assert(rcu_rbtree_is_nil(rbtree
, x
->_right
) || get_parent(x
->_right
) == x
);
543 assert(rcu_rbtree_is_nil(rbtree
, x
->_left
) || get_parent(x
->_left
) == x
);
544 assert(rcu_rbtree_is_nil(rbtree
, y
->_right
) || get_parent(y
->_right
) == y
);
545 assert(rcu_rbtree_is_nil(rbtree
, y
->_left
) || get_parent(y
->_left
) == y
);
546 assert(!is_decay(rbtree
->root
));
547 assert(!is_decay(x
));
548 assert(!is_decay(y
));
549 assert(!is_decay(x
->_right
));
550 assert(!is_decay(x
->_left
));
551 assert(!is_decay(y
->_right
));
552 assert(!is_decay(y
->_left
));
557 /* non-rcu version */
559 void left_rotate(struct rcu_rbtree
*rbtree
,
560 struct rcu_rbtree_node
*x
)
562 struct rcu_rbtree_node
*y
;
566 x
->_right
= y
->_left
;
567 if (!rcu_rbtree_is_nil(rbtree
, y
->_left
))
568 set_parent(y
->_left
, x
, IS_RIGHT
);
569 set_parent(y
, get_parent(x
), get_pos(x
));
570 if (rcu_rbtree_is_nil(rbtree
, get_parent(x
)))
572 else if (x
== get_parent(x
)->_left
) {
573 get_parent(x
)->_left
= y
;
575 get_parent(x
)->_right
= y
;
578 set_parent(x
, y
, IS_LEFT
);
584 #ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
586 void right_rotate(struct rcu_rbtree
*rbtree
,
587 struct rcu_rbtree_node
*x
)
589 struct rcu_rbtree_node
*y
, *y_right
;
594 /* Now operate on new copy, decay old versions */
595 x
= dup_decay_node(rbtree
, x
);
596 y
= dup_decay_node(rbtree
, y
);
597 y_right
= dup_decay_node(rbtree
, y_right
);
599 /* Internal node modifications */
600 set_parent(y
, get_parent(x
), get_pos(x
));
601 set_parent(x
, y
, IS_RIGHT
);
602 set_right(rbtree
, y
, x
);
603 set_left(rbtree
, x
, y_right
);
605 if (!rcu_rbtree_is_nil(rbtree
, y_right
))
606 set_parent(y_right
, x
, IS_LEFT
);
609 * We only changed the relative position of x and y wrt their
610 * children, and reparented y (but are keeping the same nodes in
611 * place, so its parent does not need to have end value
614 x
->max_end
= calculate_node_max_end(rbtree
, x
);
615 y
->max_end
= calculate_node_max_end(rbtree
, y
);
617 cmm_smp_wmb(); /* write into node before publish */
619 /* External references update (visible by readers) */
620 if (rcu_rbtree_is_nil(rbtree
, get_parent(y
)))
621 _CMM_STORE_SHARED(rbtree
->root
, y
);
622 else if (get_pos(y
) == IS_RIGHT
)
623 _CMM_STORE_SHARED(get_parent(y
)->_right
, y
);
625 _CMM_STORE_SHARED(get_parent(y
)->_left
, y
);
627 /* Point children to new copy (parent only used by updates/next/prev) */
628 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
630 set_parent(y
->_left
, get_decay(get_parent(y
->_left
)),
632 if (!rcu_rbtree_is_nil(rbtree
, y_right
)) {
633 set_parent(y_right
->_left
,
634 get_decay(get_parent(y_right
->_left
)),
635 get_pos(y_right
->_left
));
636 set_parent(y_right
->_right
,
637 get_decay(get_parent(y_right
->_right
)),
638 get_pos(y_right
->_right
));
642 assert(y
== rbtree
->root
|| get_parent(y
)->_right
== y
643 || get_parent(y
)->_left
== y
);
644 assert(x
== rbtree
->root
|| get_parent(x
)->_right
== x
645 || get_parent(x
)->_left
== x
);
646 assert(rcu_rbtree_is_nil(rbtree
, x
->_left
) || get_parent(x
->_left
) == x
);
647 assert(rcu_rbtree_is_nil(rbtree
, x
->_right
) || get_parent(x
->_right
) == x
);
648 assert(rcu_rbtree_is_nil(rbtree
, y
->_left
) || get_parent(y
->_left
) == y
);
649 assert(rcu_rbtree_is_nil(rbtree
, y
->_right
) || get_parent(y
->_right
) == y
);
650 assert(!is_decay(rbtree
->root
));
651 assert(!is_decay(x
));
652 assert(!is_decay(y
));
653 assert(!is_decay(x
->_left
));
654 assert(!is_decay(x
->_right
));
655 assert(!is_decay(y
->_left
));
656 assert(!is_decay(y
->_right
));
661 /* non-rcu version */
663 void right_rotate(struct rcu_rbtree
*rbtree
,
664 struct rcu_rbtree_node
*x
)
666 struct rcu_rbtree_node
*y
;
670 x
->_left
= y
->_right
;
671 if (!rcu_rbtree_is_nil(rbtree
, y
->_right
))
672 set_parent(y
->_right
, x
, IS_LEFT
);
673 set_parent(y
, get_parent(x
), get_pos(x
));
674 if (rcu_rbtree_is_nil(rbtree
, get_parent(x
)))
676 else if (x
== get_parent(x
)->_right
) {
677 get_parent(x
)->_right
= y
;
679 get_parent(x
)->_left
= y
;
682 set_parent(x
, y
, IS_RIGHT
);
688 static void rcu_rbtree_insert_fixup(struct rcu_rbtree
*rbtree
,
689 struct rcu_rbtree_node
*z
)
691 struct rcu_rbtree_node
*y
;
693 dbg_printf("insert fixup %p\n", z
->begin
);
694 assert(!is_decay(rbtree
->root
));
696 while (get_parent(z
)->color
== COLOR_RED
) {
697 if (get_parent(z
) == get_parent(get_parent(z
))->_left
) {
698 y
= get_parent(get_parent(z
))->_right
;
699 if (y
->color
== COLOR_RED
) {
700 get_parent(z
)->color
= COLOR_BLACK
;
701 y
->color
= COLOR_BLACK
;
702 get_parent(get_parent(z
))->color
= COLOR_RED
;
703 z
= get_parent(get_parent(z
));
705 if (z
== get_parent(z
)->_right
) {
707 left_rotate(rbtree
, z
);
709 assert(!is_decay(rbtree
->root
));
711 get_parent(z
)->color
= COLOR_BLACK
;
712 get_parent(get_parent(z
))->color
= COLOR_RED
;
713 assert(!is_decay(z
));
714 assert(!is_decay(get_parent(z
)));
715 assert(!is_decay(get_parent(get_parent(z
))));
716 right_rotate(rbtree
, get_parent(get_parent(z
)));
717 assert(!is_decay(z
));
718 assert(!is_decay(rbtree
->root
));
721 y
= get_parent(get_parent(z
))->_left
;
722 if (y
->color
== COLOR_RED
) {
723 get_parent(z
)->color
= COLOR_BLACK
;
724 y
->color
= COLOR_BLACK
;
725 get_parent(get_parent(z
))->color
= COLOR_RED
;
726 z
= get_parent(get_parent(z
));
728 if (z
== get_parent(z
)->_left
) {
730 right_rotate(rbtree
, z
);
732 assert(!is_decay(rbtree
->root
));
734 get_parent(z
)->color
= COLOR_BLACK
;
735 get_parent(get_parent(z
))->color
= COLOR_RED
;
736 left_rotate(rbtree
, get_parent(get_parent(z
)));
737 assert(!is_decay(z
));
738 assert(!is_decay(rbtree
->root
));
742 rbtree
->root
->color
= COLOR_BLACK
;
746 * rcu_rbtree_insert - Insert a node in the RCU rbtree
748 * Returns 0 on success, or < 0 on error.
750 int rcu_rbtree_insert(struct rcu_rbtree
*rbtree
,
751 struct rcu_rbtree_node
*z
)
753 struct rcu_rbtree_node
*x
, *y
;
755 dbg_printf("insert %p\n", z
->begin
);
756 assert(!is_decay(rbtree
->root
));
758 y
= make_nil(rbtree
);
760 while (!rcu_rbtree_is_nil(rbtree
, x
)) {
762 if (rbtree
->comp(z
->begin
, x
->begin
) < 0)
768 z
->_left
= make_nil(rbtree
);
769 z
->_right
= make_nil(rbtree
);
770 z
->color
= COLOR_RED
;
771 z
->decay_next
= NULL
;
774 if (rcu_rbtree_is_nil(rbtree
, y
)) {
775 set_parent(z
, y
, IS_RIGHT
); /* pos arbitrary for root node */
777 * Order stores to z (children/parents) before stores
778 * that will make it visible to the rest of the tree.
781 _CMM_STORE_SHARED(rbtree
->root
, z
);
782 } else if (rbtree
->comp(z
->begin
, y
->begin
) < 0) {
783 y
= dup_decay_node(rbtree
, y
);
784 set_parent(z
, y
, IS_LEFT
);
785 if (get_pos(z
) == IS_LEFT
)
786 _CMM_STORE_SHARED(y
->_left
, z
);
788 _CMM_STORE_SHARED(y
->_right
, z
);
789 populate_node_end(rbtree
, y
, 1, NULL
);
791 y
= dup_decay_node(rbtree
, y
);
792 set_parent(z
, y
, IS_RIGHT
);
793 if (get_pos(z
) == IS_LEFT
)
794 _CMM_STORE_SHARED(y
->_left
, z
);
796 _CMM_STORE_SHARED(y
->_right
, z
);
797 populate_node_end(rbtree
, y
, 1, NULL
);
799 rcu_rbtree_insert_fixup(rbtree
, z
);
801 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
810 * Transplant v into u position.
813 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
816 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
817 struct rcu_rbtree_node
*u
,
818 struct rcu_rbtree_node
*v
,
819 unsigned int copy_parents
,
820 struct rcu_rbtree_node
*stop
)
822 dbg_printf("transplant %p\n", v
->begin
);
824 if (!rcu_rbtree_is_nil(rbtree
, v
))
825 v
= dup_decay_node(rbtree
, v
);
827 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
))) {
828 /* pos is arbitrary for root node */
829 set_parent(v
, get_parent(u
), IS_RIGHT
);
830 cmm_smp_wmb(); /* write into node before publish */
831 _CMM_STORE_SHARED(rbtree
->root
, v
);
833 struct rcu_rbtree_node
*vp
;
837 vp
= dup_decay_node(rbtree
, vp
);
838 set_parent(v
, vp
, get_pos(u
));
839 if (get_pos(v
) == IS_LEFT
)
840 _CMM_STORE_SHARED(vp
->_left
, v
);
842 _CMM_STORE_SHARED(vp
->_right
, v
);
843 populate_node_end(rbtree
, vp
, copy_parents
, stop
);
846 /* Point children to new copy (parent only used by updates/next/prev) */
847 if (!rcu_rbtree_is_nil(rbtree
, v
)) {
848 set_parent(v
->_right
, get_decay(get_parent(v
->_right
)),
850 set_parent(v
->_left
, get_decay(get_parent(v
->_left
)),
853 assert(!is_decay(rbtree
->root
));
858 /* Non-RCU version */
860 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
861 struct rcu_rbtree_node
*u
,
862 struct rcu_rbtree_node
*v
,
863 unsigned int copy_parents
,
864 struct rcu_rbtree_node
*stop
)
866 dbg_printf("transplant %p\n", v
->begin
);
869 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
)))
871 else if (u
== get_parent(u
)->_left
)
872 get_parent(u
)->_left
= v
;
874 get_parent(u
)->_right
= v
;
875 set_parent(v
, get_parent(u
), get_pos(u
));
881 static void rcu_rbtree_remove_fixup(struct rcu_rbtree
*rbtree
,
882 struct rcu_rbtree_node
*x
)
884 dbg_printf("remove fixup %p\n", x
->begin
);
886 while (x
!= rbtree
->root
&& x
->color
== COLOR_BLACK
) {
887 assert(!is_decay(get_parent(x
)));
888 assert(!is_decay(get_parent(x
)->_left
));
889 if (x
== get_parent(x
)->_left
) {
890 struct rcu_rbtree_node
*w
;
892 w
= get_parent(x
)->_right
;
894 if (w
->color
== COLOR_RED
) {
895 w
->color
= COLOR_BLACK
;
896 get_parent(x
)->color
= COLOR_RED
;
897 left_rotate(rbtree
, get_parent(x
));
899 assert(!is_decay(rbtree
->root
));
900 w
= get_parent(x
)->_right
;
902 if (w
->_left
->color
== COLOR_BLACK
903 && w
->_right
->color
== COLOR_BLACK
) {
904 w
->color
= COLOR_RED
;
906 assert(!is_decay(rbtree
->root
));
907 assert(!is_decay(x
));
909 if (w
->_right
->color
== COLOR_BLACK
) {
910 w
->_left
->color
= COLOR_BLACK
;
911 w
->color
= COLOR_RED
;
912 right_rotate(rbtree
, w
);
913 assert(!is_decay(rbtree
->root
));
915 w
= get_parent(x
)->_right
;
917 w
->color
= get_parent(x
)->color
;
918 get_parent(x
)->color
= COLOR_BLACK
;
919 w
->_right
->color
= COLOR_BLACK
;
920 left_rotate(rbtree
, get_parent(x
));
921 assert(!is_decay(rbtree
->root
));
925 struct rcu_rbtree_node
*w
;
927 w
= get_parent(x
)->_left
;
929 if (w
->color
== COLOR_RED
) {
930 w
->color
= COLOR_BLACK
;
931 get_parent(x
)->color
= COLOR_RED
;
932 right_rotate(rbtree
, get_parent(x
));
933 assert(!is_decay(rbtree
->root
));
935 w
= get_parent(x
)->_left
;
937 if (w
->_right
->color
== COLOR_BLACK
938 && w
->_left
->color
== COLOR_BLACK
) {
939 w
->color
= COLOR_RED
;
941 assert(!is_decay(rbtree
->root
));
942 assert(!is_decay(x
));
944 if (w
->_left
->color
== COLOR_BLACK
) {
945 w
->_right
->color
= COLOR_BLACK
;
946 w
->color
= COLOR_RED
;
947 left_rotate(rbtree
, w
);
948 assert(!is_decay(rbtree
->root
));
950 w
= get_parent(x
)->_left
;
952 w
->color
= get_parent(x
)->color
;
953 get_parent(x
)->color
= COLOR_BLACK
;
954 w
->_left
->color
= COLOR_BLACK
;
955 right_rotate(rbtree
, get_parent(x
));
956 assert(!is_decay(rbtree
->root
));
961 x
->color
= COLOR_BLACK
;
965 * Delete z. All non-copied children left/right positions are unchanged.
968 void rcu_rbtree_remove_nonil(struct rcu_rbtree
*rbtree
,
969 struct rcu_rbtree_node
*z
,
970 struct rcu_rbtree_node
*y
)
972 struct rcu_rbtree_node
*x
;
974 dbg_printf("remove nonil %p\n", z
->begin
);
977 assert(!is_decay(z
));
978 assert(!is_decay(y
));
979 assert(!is_decay(y
->_right
));
980 assert(!is_decay(get_parent(y
)));
982 assert(!is_decay(x
));
983 if (get_parent(y
) == z
) {
984 y
= dup_decay_node(rbtree
, y
);
985 set_parent(x
, y
, get_pos(x
)); /* parent for nil */
986 /* y is z's right node: set left will just update y */
987 set_left(rbtree
, y
, z
->_left
);
988 rcu_rbtree_transplant(rbtree
, z
, y
, 1, NULL
);
990 struct rcu_rbtree_node
*oy_right
, *z_right
;
993 * Need to make sure y is always visible by readers.
995 y
= rcu_rbtree_min_dup_decay(rbtree
, z
->_right
, &z_right
);
996 assert(!is_decay(y
));
997 assert(!is_decay(z
));
998 oy_right
= y
->_right
;
1001 * The max child begin of z_right does not change, because
1002 * we're only changing its left children.
1004 y
->_right
= z_right
;
1005 set_parent(y
->_right
, y
, IS_RIGHT
);
1006 assert(!is_decay(z
->_left
));
1007 y
->_left
= z
->_left
;
1008 assert(!is_decay(oy_right
));
1010 * Transplant of oy_right to old y's location will only
1011 * trigger a "end" value update of the already copied branch
1012 * (which is not visible yet). We are transplanting
1013 * oy_right as a left child of old y's parent, so the
1014 * min values update propagated upward necessarily stops
1017 rcu_rbtree_transplant(rbtree
, y
, oy_right
, 0, y
);
1018 rcu_rbtree_transplant(rbtree
, z
, y
, 1, NULL
);
1019 /* Update children */
1020 (void) rcu_rbtree_min_update_decay(rbtree
, y
->_right
);
1023 assert(!is_decay(z
));
1024 assert(!is_decay(z
->_left
));
1025 y
->color
= z
->color
;
1026 set_parent(y
->_left
, y
, IS_LEFT
);
1027 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)), IS_RIGHT
);
1028 assert(!is_decay(y
->_left
));
1029 assert(!is_decay(y
->_right
));
1032 int rcu_rbtree_remove(struct rcu_rbtree
*rbtree
,
1033 struct rcu_rbtree_node
*z
)
1035 struct rcu_rbtree_node
*x
, *y
;
1036 unsigned int y_original_color
;
1038 assert(!is_decay(rbtree
->root
));
1039 dbg_printf("remove %p\n", z
->begin
);
1042 assert(!is_decay(z
));
1044 y_original_color
= y
->color
;
1046 if (rcu_rbtree_is_nil(rbtree
, z
->_left
)) {
1047 rcu_rbtree_transplant(rbtree
, z
, z
->_right
, 1, NULL
);
1048 assert(!is_decay(z
));
1049 x
= get_decay(z
->_right
);
1051 } else if (rcu_rbtree_is_nil(rbtree
, z
->_right
)) {
1052 rcu_rbtree_transplant(rbtree
, z
, z
->_left
, 1, NULL
);
1053 assert(!is_decay(z
));
1054 x
= get_decay(z
->_left
);
1057 y
= rcu_rbtree_min(rbtree
, z
->_right
);
1058 assert(!is_decay(y
));
1059 y_original_color
= y
->color
;
1061 rcu_rbtree_remove_nonil(rbtree
, z
, y
);
1065 if (y_original_color
== COLOR_BLACK
)
1066 rcu_rbtree_remove_fixup(rbtree
, x
);
1069 * Commit all _CMM_STORE_SHARED().