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 pe: %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) get_parent(node
)->end
,
201 (unsigned long) node
->_right
->key
,
202 (unsigned long) node
->_left
->key
,
203 node
->color
? "red" : "black",
204 get_pos(node
) ? "right" : "left",
205 rcu_rbtree_is_nil(rbtree
, node
) ? "nil" : "");
206 node
= rcu_rbtree_next(rbtree
, node
);
212 void show_tree(struct rcu_rbtree
*rbtree
)
218 struct rcu_rbtree_node
*make_nil(struct rcu_rbtree
*rbtree
)
220 return &rbtree
->nil_node
;
224 * Iterative rbtree search.
226 struct rcu_rbtree_node
*rcu_rbtree_search(struct rcu_rbtree
*rbtree
,
227 struct rcu_rbtree_node
*x
,
230 x
= rcu_dereference(x
);
233 while (!rcu_rbtree_is_nil(rbtree
, x
) && (comp
= rbtree
->comp(k
, x
->begin
)) != 0) {
236 x
= rcu_dereference(x
->_left
);
238 x
= rcu_dereference(x
->_right
);
244 struct rcu_rbtree_node
*rcu_rbtree_min_dup_decay(struct rcu_rbtree
*rbtree
,
245 struct rcu_rbtree_node
*x
,
246 struct rcu_rbtree_node
**zr
)
248 struct rcu_rbtree_node
*xl
;
250 x
= rcu_dereference(x
);
252 if (rcu_rbtree_is_nil(rbtree
, x
)) {
256 *zr
= x
= dup_decay_node(rbtree
, x
);
258 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
))) {
259 x
= dup_decay_node(rbtree
, xl
);
260 set_parent(x
, get_decay(get_parent(x
)), get_pos(x
));
261 get_parent(x
)->_left
= get_decay(get_parent(x
)->_left
);
267 struct rcu_rbtree_node
*rcu_rbtree_min_update_decay(struct rcu_rbtree
*rbtree
,
268 struct rcu_rbtree_node
*x
)
270 struct rcu_rbtree_node
*xl
;
272 x
= rcu_dereference(x
);
274 if (rcu_rbtree_is_nil(rbtree
, x
))
277 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
279 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
283 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
))) {
285 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
287 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
293 struct rcu_rbtree_node
*rcu_rbtree_min(struct rcu_rbtree
*rbtree
,
294 struct rcu_rbtree_node
*x
)
296 struct rcu_rbtree_node
*xl
;
298 x
= rcu_dereference(x
);
300 if (rcu_rbtree_is_nil(rbtree
, x
))
303 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
)))
308 struct rcu_rbtree_node
*rcu_rbtree_max(struct rcu_rbtree
*rbtree
,
309 struct rcu_rbtree_node
*x
)
311 struct rcu_rbtree_node
*xr
;
313 x
= rcu_dereference(x
);
315 if (rcu_rbtree_is_nil(rbtree
, x
))
318 while (!rcu_rbtree_is_nil(rbtree
, xr
= rcu_dereference(x
->_right
)))
325 * Updates should wait for a grace period between update of the
326 * redirect pointer and update of the parent child pointer. This is to make sure
327 * that no reference to the old entry exist.
331 * RCU read lock must be held across the next/prev calls to ensure validity of
334 struct rcu_rbtree_node
*rcu_rbtree_next(struct rcu_rbtree
*rbtree
,
335 struct rcu_rbtree_node
*x
)
337 struct rcu_rbtree_node
*xr
, *y
;
340 x
= rcu_dereference(x
);
342 if (!rcu_rbtree_is_nil(rbtree
, xr
= rcu_dereference(x
->_right
)))
343 return rcu_rbtree_min(rbtree
, xr
);
344 y
= get_parent_and_pos(x
, &x_pos
);
345 while (!rcu_rbtree_is_nil(rbtree
, y
) && x_pos
== IS_RIGHT
) {
347 y
= get_parent_and_pos(y
, &x_pos
);
352 struct rcu_rbtree_node
*rcu_rbtree_prev(struct rcu_rbtree
*rbtree
,
353 struct rcu_rbtree_node
*x
)
355 struct rcu_rbtree_node
*xl
, *y
;
358 x
= rcu_dereference(x
);
360 if (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
)))
361 return rcu_rbtree_max(rbtree
, xl
);
362 y
= get_parent_and_pos(x
, &x_pos
);
363 while (!rcu_rbtree_is_nil(rbtree
, y
) && x_pos
== IS_LEFT
) {
365 y
= get_parent_and_pos(y
, &x_pos
);
371 * "node" needs to be non-visible by readers.
374 void populate_node_end(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
,
377 struct rcu_rbtree_node
*prev
= NULL
, *orig_node
= node
, *top
;
382 assert(!rcu_rbtree_is_nil(rbtree
, node
));
384 if (!rcu_rbtree_is_nil(rbtree
, node
->_right
))
385 max_end
= max(max_end
, node
->_right
->max_end
);
386 if (!rcu_rbtree_is_nil(rbtree
, node
->_left
))
387 max_end
= max(max_end
, node
->_left
->max_end
);
389 if (max_end
!= node
->max_end
) {
391 node
= dup_decay_node(rbtree
, node
);
392 if (get_pos(prev
) == IS_RIGHT
)
396 set_parent(prev
, node
, get_pos(prev
));
398 node
->max_end
= max_end
;
401 * We did not have to change the current node,
402 * so set the pointer to the prev node. If prev
403 * was null, this means we are coming in the
404 * first loop, and must update the parent of the
405 * node received as parameter (node).
409 top
= get_parent(node
);
410 cmm_smp_wmb(); /* write into node before publish */
411 /* make new branch visible to readers */
412 if (rcu_rbtree_is_nil(rbtree
, top
))
413 _CMM_STORE_SHARED(rbtree
->root
, node
);
414 if (get_pos(node
) == IS_LEFT
)
415 _CMM_STORE_SHARED(top
->_left
, node
);
417 _CMM_STORE_SHARED(top
->_right
, node
);
421 } while (!rcu_rbtree_is_nil(rbtree
, node
= get_parent(node
)));
423 top
= node
; /* nil */
424 cmm_smp_wmb(); /* write into node before publish */
425 /* make new branch visible to readers */
426 _CMM_STORE_SHARED(rbtree
->root
, prev
);
429 /* update children */
432 assert(!rcu_rbtree_is_nil(rbtree
, node
));
433 set_parent(node
->_left
, get_decay(get_parent(node
->_left
)), IS_LEFT
);
434 set_parent(node
->_right
, get_decay(get_parent(node
->_right
)), IS_RIGHT
);
435 } while ((node
= get_parent(node
)) != top
);
439 * We have to ensure these assumptions are correct for prev/next
442 * with x being a right child, the assumption that:
443 * get_parent(x)->_right == x
444 * or if x is a left child, the assumption that:
445 * get_parent(x)->_left == x
447 * This explains why we have to allocate a vc copy of the node for left_rotate,
448 * right_rotate and transplant operations.
450 * We always ensure that the right/left child and correct parent is set in the
451 * node copies *before* we reparent the children and make the upper-level point
455 /* RCU: copy x and y, atomically point to new versions. GC old. */
456 /* Should be eventually followed by a cmm_smp_wmc() */
458 #ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
461 void left_rotate(struct rcu_rbtree
*rbtree
,
462 struct rcu_rbtree_node
*x
)
464 struct rcu_rbtree_node
*y
, *y_left
;
469 /* Now operate on new copy, decay old versions */
470 x
= dup_decay_node(rbtree
, x
);
471 y
= dup_decay_node(rbtree
, y
);
472 y_left
= dup_decay_node(rbtree
, y_left
);
474 /* Internal node modifications */
475 set_parent(y
, get_parent(x
), get_pos(x
));
476 set_parent(x
, y
, IS_LEFT
);
477 set_left(rbtree
, y
, x
);
478 set_right(rbtree
, x
, y_left
);
480 if (!rcu_rbtree_is_nil(rbtree
, y_left
))
481 set_parent(y_left
, x
, IS_RIGHT
);
483 cmm_smp_wmb(); /* write into node before publish */
485 /* External references update (visible by readers) */
486 if (rcu_rbtree_is_nil(rbtree
, get_parent(y
)))
487 _CMM_STORE_SHARED(rbtree
->root
, y
);
488 else if (get_pos(y
) == IS_LEFT
)
489 _CMM_STORE_SHARED(get_parent(y
)->_left
, y
);
491 _CMM_STORE_SHARED(get_parent(y
)->_right
, y
);
493 /* Point children to new copy (parent only used by updates/next/prev) */
494 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
496 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)),
498 if (!rcu_rbtree_is_nil(rbtree
, y_left
)) {
499 set_parent(y_left
->_right
,
500 get_decay(get_parent(y_left
->_right
)),
501 get_pos(y_left
->_right
));
502 set_parent(y_left
->_left
,
503 get_decay(get_parent(y_left
->_left
)),
504 get_pos(y_left
->_left
));
508 assert(y
== rbtree
->root
|| get_parent(y
)->_left
== y
509 || get_parent(y
)->_right
== y
);
510 assert(x
== rbtree
->root
|| get_parent(x
)->_left
== x
511 || get_parent(x
)->_right
== x
);
512 assert(rcu_rbtree_is_nil(rbtree
, x
->_right
) || get_parent(x
->_right
) == x
);
513 assert(rcu_rbtree_is_nil(rbtree
, x
->_left
) || get_parent(x
->_left
) == x
);
514 assert(rcu_rbtree_is_nil(rbtree
, y
->_right
) || get_parent(y
->_right
) == y
);
515 assert(rcu_rbtree_is_nil(rbtree
, y
->_left
) || get_parent(y
->_left
) == y
);
516 assert(!is_decay(rbtree
->root
));
517 assert(!is_decay(x
));
518 assert(!is_decay(y
));
519 assert(!is_decay(x
->_right
));
520 assert(!is_decay(x
->_left
));
521 assert(!is_decay(y
->_right
));
522 assert(!is_decay(y
->_left
));
527 /* non-rcu version */
529 void left_rotate(struct rcu_rbtree
*rbtree
,
530 struct rcu_rbtree_node
*x
)
532 struct rcu_rbtree_node
*y
;
536 x
->_right
= y
->_left
;
537 if (!rcu_rbtree_is_nil(rbtree
, y
->_left
))
538 set_parent(y
->_left
, x
, IS_RIGHT
);
539 set_parent(y
, get_parent(x
), get_pos(x
));
540 if (rcu_rbtree_is_nil(rbtree
, get_parent(x
)))
542 else if (x
== get_parent(x
)->_left
) {
543 get_parent(x
)->_left
= y
;
545 get_parent(x
)->_right
= y
;
548 set_parent(x
, y
, IS_LEFT
);
554 #ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
556 void right_rotate(struct rcu_rbtree
*rbtree
,
557 struct rcu_rbtree_node
*x
)
559 struct rcu_rbtree_node
*y
, *y_right
;
564 /* Now operate on new copy, decay old versions */
565 x
= dup_decay_node(rbtree
, x
);
566 y
= dup_decay_node(rbtree
, y
);
567 y_right
= dup_decay_node(rbtree
, y_right
);
569 /* Internal node modifications */
570 set_parent(y
, get_parent(x
), get_pos(x
));
571 set_parent(x
, y
, IS_RIGHT
);
572 set_right(rbtree
, y
, x
);
573 set_left(rbtree
, x
, y_right
);
575 if (!rcu_rbtree_is_nil(rbtree
, y_right
))
576 set_parent(y_right
, x
, IS_LEFT
);
578 cmm_smp_wmb(); /* write into node before publish */
580 /* External references update (visible by readers) */
581 if (rcu_rbtree_is_nil(rbtree
, get_parent(y
)))
582 _CMM_STORE_SHARED(rbtree
->root
, y
);
583 else if (get_pos(y
) == IS_RIGHT
)
584 _CMM_STORE_SHARED(get_parent(y
)->_right
, y
);
586 _CMM_STORE_SHARED(get_parent(y
)->_left
, y
);
588 /* Point children to new copy (parent only used by updates/next/prev) */
589 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
591 set_parent(y
->_left
, get_decay(get_parent(y
->_left
)),
593 if (!rcu_rbtree_is_nil(rbtree
, y_right
)) {
594 set_parent(y_right
->_left
,
595 get_decay(get_parent(y_right
->_left
)),
596 get_pos(y_right
->_left
));
597 set_parent(y_right
->_right
,
598 get_decay(get_parent(y_right
->_right
)),
599 get_pos(y_right
->_right
));
603 assert(y
== rbtree
->root
|| get_parent(y
)->_right
== y
604 || get_parent(y
)->_left
== y
);
605 assert(x
== rbtree
->root
|| get_parent(x
)->_right
== x
606 || get_parent(x
)->_left
== x
);
607 assert(rcu_rbtree_is_nil(rbtree
, x
->_left
) || get_parent(x
->_left
) == x
);
608 assert(rcu_rbtree_is_nil(rbtree
, x
->_right
) || get_parent(x
->_right
) == x
);
609 assert(rcu_rbtree_is_nil(rbtree
, y
->_left
) || get_parent(y
->_left
) == y
);
610 assert(rcu_rbtree_is_nil(rbtree
, y
->_right
) || get_parent(y
->_right
) == y
);
611 assert(!is_decay(rbtree
->root
));
612 assert(!is_decay(x
));
613 assert(!is_decay(y
));
614 assert(!is_decay(x
->_left
));
615 assert(!is_decay(x
->_right
));
616 assert(!is_decay(y
->_left
));
617 assert(!is_decay(y
->_right
));
622 /* non-rcu version */
624 void right_rotate(struct rcu_rbtree
*rbtree
,
625 struct rcu_rbtree_node
*x
)
627 struct rcu_rbtree_node
*y
;
631 x
->_left
= y
->_right
;
632 if (!rcu_rbtree_is_nil(rbtree
, y
->_right
))
633 set_parent(y
->_right
, x
, IS_LEFT
);
634 set_parent(y
, get_parent(x
), get_pos(x
));
635 if (rcu_rbtree_is_nil(rbtree
, get_parent(x
)))
637 else if (x
== get_parent(x
)->_right
) {
638 get_parent(x
)->_right
= y
;
640 get_parent(x
)->_left
= y
;
643 set_parent(x
, y
, IS_RIGHT
);
649 static void rcu_rbtree_insert_fixup(struct rcu_rbtree
*rbtree
,
650 struct rcu_rbtree_node
*z
)
652 struct rcu_rbtree_node
*y
;
654 dbg_printf("insert fixup %p\n", z
->begin
);
655 assert(!is_decay(rbtree
->root
));
657 while (get_parent(z
)->color
== COLOR_RED
) {
658 if (get_parent(z
) == get_parent(get_parent(z
))->_left
) {
659 y
= get_parent(get_parent(z
))->_right
;
660 if (y
->color
== COLOR_RED
) {
661 get_parent(z
)->color
= COLOR_BLACK
;
662 y
->color
= COLOR_BLACK
;
663 get_parent(get_parent(z
))->color
= COLOR_RED
;
664 z
= get_parent(get_parent(z
));
666 if (z
== get_parent(z
)->_right
) {
668 left_rotate(rbtree
, z
);
670 assert(!is_decay(rbtree
->root
));
672 get_parent(z
)->color
= COLOR_BLACK
;
673 get_parent(get_parent(z
))->color
= COLOR_RED
;
674 assert(!is_decay(z
));
675 assert(!is_decay(get_parent(z
)));
676 assert(!is_decay(get_parent(get_parent(z
))));
677 right_rotate(rbtree
, get_parent(get_parent(z
)));
678 assert(!is_decay(z
));
679 assert(!is_decay(rbtree
->root
));
682 y
= get_parent(get_parent(z
))->_left
;
683 if (y
->color
== COLOR_RED
) {
684 get_parent(z
)->color
= COLOR_BLACK
;
685 y
->color
= COLOR_BLACK
;
686 get_parent(get_parent(z
))->color
= COLOR_RED
;
687 z
= get_parent(get_parent(z
));
689 if (z
== get_parent(z
)->_left
) {
691 right_rotate(rbtree
, z
);
693 assert(!is_decay(rbtree
->root
));
695 get_parent(z
)->color
= COLOR_BLACK
;
696 get_parent(get_parent(z
))->color
= COLOR_RED
;
697 left_rotate(rbtree
, get_parent(get_parent(z
)));
698 assert(!is_decay(z
));
699 assert(!is_decay(rbtree
->root
));
703 rbtree
->root
->color
= COLOR_BLACK
;
707 * rcu_rbtree_insert - Insert a node in the RCU rbtree
709 * Returns 0 on success, or < 0 on error.
711 int rcu_rbtree_insert(struct rcu_rbtree
*rbtree
,
712 struct rcu_rbtree_node
*z
)
714 struct rcu_rbtree_node
*x
, *y
;
716 dbg_printf("insert %p\n", z
->begin
);
717 assert(!is_decay(rbtree
->root
));
719 y
= make_nil(rbtree
);
721 while (!rcu_rbtree_is_nil(rbtree
, x
)) {
723 if (rbtree
->comp(z
->begin
, x
->begin
) < 0)
729 z
->_left
= make_nil(rbtree
);
730 z
->_right
= make_nil(rbtree
);
731 z
->color
= COLOR_RED
;
732 z
->decay_next
= NULL
;
735 if (rcu_rbtree_is_nil(rbtree
, y
)) {
736 set_parent(z
, y
, IS_RIGHT
); /* pos arbitrary for root node */
738 * Order stores to z (children/parents) before stores
739 * that will make it visible to the rest of the tree.
742 _CMM_STORE_SHARED(rbtree
->root
, z
);
743 } else if (rbtree
->comp(z
->begin
, y
->begin
) < 0) {
744 y
= dup_decay_node(rbtree
, y
);
745 set_parent(z
, y
, IS_LEFT
);
746 if (get_pos(z
) == IS_LEFT
)
747 _CMM_STORE_SHARED(y
->_left
, z
);
749 _CMM_STORE_SHARED(y
->_right
, z
);
750 populate_node_end(rbtree
, y
, 1);
752 y
= dup_decay_node(rbtree
, y
);
753 set_parent(z
, y
, IS_RIGHT
);
754 if (get_pos(z
) == IS_LEFT
)
755 _CMM_STORE_SHARED(y
->_left
, z
);
757 _CMM_STORE_SHARED(y
->_right
, z
);
758 populate_node_end(rbtree
, y
, 1);
760 rcu_rbtree_insert_fixup(rbtree
, z
);
762 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
771 * Transplant v into u position.
774 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
777 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
778 struct rcu_rbtree_node
*u
,
779 struct rcu_rbtree_node
*v
,
780 unsigned int copy_parents
)
782 dbg_printf("transplant %p\n", v
->begin
);
784 if (!rcu_rbtree_is_nil(rbtree
, v
))
785 v
= dup_decay_node(rbtree
, v
);
787 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
))) {
788 /* pos is arbitrary for root node */
789 set_parent(v
, get_parent(u
), IS_RIGHT
);
790 cmm_smp_wmb(); /* write into node before publish */
791 _CMM_STORE_SHARED(rbtree
->root
, v
);
793 set_parent(v
, get_parent(u
), get_pos(u
));
794 cmm_smp_wmb(); /* write into node before publish */
796 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
)))
797 _CMM_STORE_SHARED(rbtree
->root
, v
);
798 else if (get_pos(u
) == IS_LEFT
)
799 _CMM_STORE_SHARED(get_parent(u
)->_left
, v
);
801 _CMM_STORE_SHARED(get_parent(u
)->_right
, v
);
804 /* Point children to new copy (parent only used by updates/next/prev) */
805 if (!rcu_rbtree_is_nil(rbtree
, v
)) {
806 set_parent(v
->_right
, get_decay(get_parent(v
->_right
)),
808 set_parent(v
->_left
, get_decay(get_parent(v
->_left
)),
811 assert(!is_decay(rbtree
->root
));
816 /* Non-RCU version */
818 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
819 struct rcu_rbtree_node
*u
,
820 struct rcu_rbtree_node
*v
,
821 unsigned int copy_parents
)
823 dbg_printf("transplant %p\n", v
->begin
);
826 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
)))
828 else if (u
== get_parent(u
)->_left
)
829 get_parent(u
)->_left
= v
;
831 get_parent(u
)->_right
= v
;
832 set_parent(v
, get_parent(u
), get_pos(u
));
838 static void rcu_rbtree_remove_fixup(struct rcu_rbtree
*rbtree
,
839 struct rcu_rbtree_node
*x
)
841 dbg_printf("remove fixup %p\n", x
->begin
);
843 while (x
!= rbtree
->root
&& x
->color
== COLOR_BLACK
) {
844 assert(!is_decay(get_parent(x
)));
845 assert(!is_decay(get_parent(x
)->_left
));
846 if (x
== get_parent(x
)->_left
) {
847 struct rcu_rbtree_node
*w
;
849 w
= get_parent(x
)->_right
;
851 if (w
->color
== COLOR_RED
) {
852 w
->color
= COLOR_BLACK
;
853 get_parent(x
)->color
= COLOR_RED
;
854 left_rotate(rbtree
, get_parent(x
));
856 assert(!is_decay(rbtree
->root
));
857 w
= get_parent(x
)->_right
;
859 if (w
->_left
->color
== COLOR_BLACK
860 && w
->_right
->color
== COLOR_BLACK
) {
861 w
->color
= COLOR_RED
;
863 assert(!is_decay(rbtree
->root
));
864 assert(!is_decay(x
));
866 if (w
->_right
->color
== COLOR_BLACK
) {
867 w
->_left
->color
= COLOR_BLACK
;
868 w
->color
= COLOR_RED
;
869 right_rotate(rbtree
, w
);
870 assert(!is_decay(rbtree
->root
));
872 w
= get_parent(x
)->_right
;
874 w
->color
= get_parent(x
)->color
;
875 get_parent(x
)->color
= COLOR_BLACK
;
876 w
->_right
->color
= COLOR_BLACK
;
877 left_rotate(rbtree
, get_parent(x
));
878 assert(!is_decay(rbtree
->root
));
882 struct rcu_rbtree_node
*w
;
884 w
= get_parent(x
)->_left
;
886 if (w
->color
== COLOR_RED
) {
887 w
->color
= COLOR_BLACK
;
888 get_parent(x
)->color
= COLOR_RED
;
889 right_rotate(rbtree
, get_parent(x
));
890 assert(!is_decay(rbtree
->root
));
892 w
= get_parent(x
)->_left
;
894 if (w
->_right
->color
== COLOR_BLACK
895 && w
->_left
->color
== COLOR_BLACK
) {
896 w
->color
= COLOR_RED
;
898 assert(!is_decay(rbtree
->root
));
899 assert(!is_decay(x
));
901 if (w
->_left
->color
== COLOR_BLACK
) {
902 w
->_right
->color
= COLOR_BLACK
;
903 w
->color
= COLOR_RED
;
904 left_rotate(rbtree
, w
);
905 assert(!is_decay(rbtree
->root
));
907 w
= get_parent(x
)->_left
;
909 w
->color
= get_parent(x
)->color
;
910 get_parent(x
)->color
= COLOR_BLACK
;
911 w
->_left
->color
= COLOR_BLACK
;
912 right_rotate(rbtree
, get_parent(x
));
913 assert(!is_decay(rbtree
->root
));
918 x
->color
= COLOR_BLACK
;
922 * Delete z. All non-copied children left/right positions are unchanged.
925 void rcu_rbtree_remove_nonil(struct rcu_rbtree
*rbtree
,
926 struct rcu_rbtree_node
*z
,
927 struct rcu_rbtree_node
*y
)
929 struct rcu_rbtree_node
*x
;
931 dbg_printf("remove nonil %p\n", z
->begin
);
934 assert(!is_decay(z
));
935 assert(!is_decay(y
));
936 assert(!is_decay(y
->_right
));
937 assert(!is_decay(get_parent(y
)));
939 assert(!is_decay(x
));
940 if (get_parent(y
) == z
) {
941 y
= dup_decay_node(rbtree
, y
);
942 set_parent(x
, y
, get_pos(x
)); /* parent for nil */
943 /* y is z's right node: set left will just update y */
944 set_left(rbtree
, y
, z
->_left
);
945 rcu_rbtree_transplant(rbtree
, z
, y
, 1);
947 struct rcu_rbtree_node
*oy_right
, *z_right
;
950 * Need to make sure y is always visible by readers.
952 y
= rcu_rbtree_min_dup_decay(rbtree
, z
->_right
, &z_right
);
953 assert(!is_decay(y
));
954 assert(!is_decay(z
));
955 oy_right
= y
->_right
;
958 * The max child begin of z_right does not change, because
959 * we're only changing its left children.
962 set_parent(y
->_right
, y
, IS_RIGHT
);
963 assert(!is_decay(z
->_left
));
965 assert(!is_decay(oy_right
));
967 * Transplant of oy_right to old y's location will only
968 * trigger a min/max update of the already copied branch
969 * (which is not visible yet). We are transplanting
970 * oy_right as a left child of old y's parent, so the
971 * min values update propagated upward necessarily stops
974 rcu_rbtree_transplant(rbtree
, y
, oy_right
, 0);
975 rcu_rbtree_transplant(rbtree
, z
, y
, 1);
976 /* Update children */
977 (void) rcu_rbtree_min_update_decay(rbtree
, y
->_right
);
980 assert(!is_decay(z
));
981 assert(!is_decay(z
->_left
));
983 set_parent(y
->_left
, y
, IS_LEFT
);
984 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)), IS_RIGHT
);
985 assert(!is_decay(y
->_left
));
986 assert(!is_decay(y
->_right
));
989 int rcu_rbtree_remove(struct rcu_rbtree
*rbtree
,
990 struct rcu_rbtree_node
*z
)
992 struct rcu_rbtree_node
*x
, *y
;
993 unsigned int y_original_color
;
995 assert(!is_decay(rbtree
->root
));
996 dbg_printf("remove %p\n", z
->begin
);
999 assert(!is_decay(z
));
1001 y_original_color
= y
->color
;
1003 if (rcu_rbtree_is_nil(rbtree
, z
->_left
)) {
1004 rcu_rbtree_transplant(rbtree
, z
, z
->_right
, 1);
1005 assert(!is_decay(z
));
1006 x
= get_decay(z
->_right
);
1008 } else if (rcu_rbtree_is_nil(rbtree
, z
->_right
)) {
1009 rcu_rbtree_transplant(rbtree
, z
, z
->_left
, 1);
1010 assert(!is_decay(z
));
1011 x
= get_decay(z
->_left
);
1014 y
= rcu_rbtree_min(rbtree
, z
->_right
);
1015 assert(!is_decay(y
));
1016 y_original_color
= y
->color
;
1018 rcu_rbtree_remove_nonil(rbtree
, z
, y
);
1022 if (y_original_color
== COLOR_BLACK
)
1023 rcu_rbtree_remove_fixup(rbtree
, x
);
1026 * Commit all _CMM_STORE_SHARED().