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
;
180 void *calculate_node_max_end(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
)
185 if (!rcu_rbtree_is_nil(rbtree
, node
->_right
)) {
186 if (rbtree
->comp(max_end
, node
->_right
->max_end
) < 0)
187 max_end
= node
->_right
->max_end
;
189 if (!rcu_rbtree_is_nil(rbtree
, node
->_left
)) {
190 if (rbtree
->comp(max_end
, node
->_left
->max_end
) < 0)
191 max_end
= node
->_left
->max_end
;
198 * Deal with memory allocation errors.
199 * Can be ensured by reserving a pool of memory entries before doing the
200 * insertion, which will have to be function of number of
201 * transplantations/rotations required for the operation (which is a
202 * multiple of the tree height).
207 void show_tree(struct rcu_rbtree
*rbtree
)
209 struct rcu_rbtree_node
*node
;
211 node
= rcu_rbtree_min(rbtree
, rbtree
->root
);
212 while (!rcu_rbtree_is_nil(rbtree
, node
)) {
213 assert(!is_decay(node
));
214 printf("{ b:%lX e:%lX pb: %lX r:%lX l:%lX %s %s %s} ",
215 (unsigned long) node
->begin
,
216 (unsigned long) node
->end
,
217 (unsigned long) get_parent(node
)->begin
,
218 (unsigned long) node
->_right
->begin
,
219 (unsigned long) node
->_left
->begin
,
220 node
->color
? "red" : "black",
221 get_pos(node
) ? "right" : "left",
222 rcu_rbtree_is_nil(rbtree
, node
) ? "nil" : "");
223 node
= rcu_rbtree_next(rbtree
, node
);
228 #define check_max_end(rbtree, x) \
230 if (rcu_rbtree_is_nil(rbtree, x)) \
232 assert(rbtree->comp(x->max_end, \
233 calculate_node_max_end(rbtree, x)) == 0); \
238 void show_tree(struct rcu_rbtree
*rbtree
)
243 void check_max_end(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*x
)
249 struct rcu_rbtree_node
*make_nil(struct rcu_rbtree
*rbtree
)
251 return &rbtree
->nil_node
;
255 * Iterative rbtree search.
257 struct rcu_rbtree_node
*rcu_rbtree_search(struct rcu_rbtree
*rbtree
,
258 struct rcu_rbtree_node
*x
,
261 struct rcu_rbtree_node
*xl
;
263 dbg_printf("searching point 0x%lx\n", (unsigned long) point
);
264 x
= rcu_dereference(x
);
266 while (!rcu_rbtree_is_nil(rbtree
, x
)) {
268 xl
= rcu_dereference(x
->_left
);
269 dbg_printf("search x %lx x_end %lx x_max_end %lx\n", (unsigned long) x
->begin
,
270 (unsigned long) x
->end
, (unsigned long) x
->max_end
);
271 dbg_printf("search xl %lx xl_end %lx xl_max_end %lx\n", (unsigned long) xl
->begin
,
272 (unsigned long) xl
->end
, (unsigned long) xl
->max_end
);
273 if (!rcu_rbtree_is_nil(rbtree
, xl
)
274 && (rbtree
->comp(xl
->max_end
, point
) > 0)) {
275 dbg_printf("go left\n");
277 } else if (rbtree
->comp(x
->begin
, point
) >= 0
278 && rbtree
->comp(point
, x
->end
) < 0) {
279 dbg_printf("got it!\n");
281 } else if (rbtree
->comp(point
, x
->begin
) > 0) {
282 dbg_printf("go right\n");
283 x
= rcu_dereference(x
->_right
);
285 dbg_printf("not found!\n");
286 x
= make_nil(rbtree
);
289 if (rcu_rbtree_is_nil(rbtree
, x
))
290 dbg_printf("Reached bottom of tree.\n");
295 struct rcu_rbtree_node
*rcu_rbtree_search_range(struct rcu_rbtree
*rbtree
,
296 struct rcu_rbtree_node
*x
,
297 void *begin
, void *end
)
299 struct rcu_rbtree_node
*node
;
301 node
= rcu_rbtree_search(rbtree
, x
, begin
);
302 if (rcu_rbtree_is_nil(rbtree
, node
))
304 if (rbtree
->comp(node
->end
, end
) < 0)
305 return NULL
; /* High is outside lookup range */
310 * Search by exact range start value.
312 struct rcu_rbtree_node
*rcu_rbtree_search_begin_key(struct rcu_rbtree
*rbtree
,
313 struct rcu_rbtree_node
*x
,
316 x
= rcu_dereference(x
);
319 while (!rcu_rbtree_is_nil(rbtree
, x
) && (comp
= rbtree
->comp(k
, x
->begin
)) != 0) {
322 x
= rcu_dereference(x
->_left
);
324 x
= rcu_dereference(x
->_right
);
330 struct rcu_rbtree_node
*rcu_rbtree_min_dup_decay(struct rcu_rbtree
*rbtree
,
331 struct rcu_rbtree_node
*x
,
332 struct rcu_rbtree_node
**zr
)
334 struct rcu_rbtree_node
*xl
;
336 x
= rcu_dereference(x
);
338 if (rcu_rbtree_is_nil(rbtree
, x
)) {
342 *zr
= x
= dup_decay_node(rbtree
, x
);
344 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
))) {
345 x
= dup_decay_node(rbtree
, xl
);
346 set_parent(x
, get_decay(get_parent(x
)), get_pos(x
));
347 get_parent(x
)->_left
= get_decay(get_parent(x
)->_left
);
353 struct rcu_rbtree_node
*rcu_rbtree_min_update_decay(struct rcu_rbtree
*rbtree
,
354 struct rcu_rbtree_node
*x
)
356 struct rcu_rbtree_node
*xl
;
358 x
= rcu_dereference(x
);
360 if (rcu_rbtree_is_nil(rbtree
, x
))
363 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
365 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
369 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
))) {
371 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
373 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
379 struct rcu_rbtree_node
*rcu_rbtree_min(struct rcu_rbtree
*rbtree
,
380 struct rcu_rbtree_node
*x
)
382 struct rcu_rbtree_node
*xl
;
384 x
= rcu_dereference(x
);
386 if (rcu_rbtree_is_nil(rbtree
, x
))
389 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
)))
394 struct rcu_rbtree_node
*rcu_rbtree_max(struct rcu_rbtree
*rbtree
,
395 struct rcu_rbtree_node
*x
)
397 struct rcu_rbtree_node
*xr
;
399 x
= rcu_dereference(x
);
401 if (rcu_rbtree_is_nil(rbtree
, x
))
404 while (!rcu_rbtree_is_nil(rbtree
, xr
= rcu_dereference(x
->_right
)))
411 * Updates should wait for a grace period between update of the
412 * redirect pointer and update of the parent child pointer. This is to make sure
413 * that no reference to the old entry exist.
417 * RCU read lock must be held across the next/prev calls to ensure validity of
420 struct rcu_rbtree_node
*rcu_rbtree_next(struct rcu_rbtree
*rbtree
,
421 struct rcu_rbtree_node
*x
)
423 struct rcu_rbtree_node
*xr
, *y
;
426 x
= rcu_dereference(x
);
428 if (!rcu_rbtree_is_nil(rbtree
, xr
= rcu_dereference(x
->_right
)))
429 return rcu_rbtree_min(rbtree
, xr
);
430 y
= get_parent_and_pos(x
, &x_pos
);
431 while (!rcu_rbtree_is_nil(rbtree
, y
) && x_pos
== IS_RIGHT
) {
433 y
= get_parent_and_pos(y
, &x_pos
);
438 struct rcu_rbtree_node
*rcu_rbtree_prev(struct rcu_rbtree
*rbtree
,
439 struct rcu_rbtree_node
*x
)
441 struct rcu_rbtree_node
*xl
, *y
;
444 x
= rcu_dereference(x
);
446 if (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
)))
447 return rcu_rbtree_max(rbtree
, xl
);
448 y
= get_parent_and_pos(x
, &x_pos
);
449 while (!rcu_rbtree_is_nil(rbtree
, y
) && x_pos
== IS_LEFT
) {
451 y
= get_parent_and_pos(y
, &x_pos
);
457 * "node" needs to be non-visible by readers.
460 void populate_node_end(struct rcu_rbtree
*rbtree
, struct rcu_rbtree_node
*node
,
461 unsigned int copy_parents
, struct rcu_rbtree_node
*stop
)
463 struct rcu_rbtree_node
*prev
= NULL
, *orig_node
= node
, *top
;
469 assert(!rcu_rbtree_is_nil(rbtree
, node
));
471 if (prev
&& copy_parents
) {
472 node
= dup_decay_node(rbtree
, node
);
473 if (get_pos(prev
) == IS_RIGHT
)
477 set_parent(prev
, node
, get_pos(prev
));
480 max_end
= calculate_node_max_end(rbtree
, node
);
482 * Compare the node max_end keys to make sure we replace
483 * references to a key belonging to a node we remove
484 * from the tree. Otherwise we would still be using this
485 * pointer as an invalid reference after garbage
486 * collection of the node and of its associated
487 * begin/end pointers.
489 if (max_end
!= node
->max_end
) {
490 node
->max_end
= max_end
;
492 top
= get_parent(node
);
493 cmm_smp_wmb(); /* write into node before publish */
494 /* make new branch visible to readers */
495 if (rcu_rbtree_is_nil(rbtree
, top
))
496 _CMM_STORE_SHARED(rbtree
->root
, node
);
497 if (get_pos(node
) == IS_LEFT
)
498 _CMM_STORE_SHARED(top
->_left
, node
);
500 _CMM_STORE_SHARED(top
->_right
, node
);
504 /* Check for propagation stop */
509 node
= get_parent(node
);
510 } while (!rcu_rbtree_is_nil(rbtree
, node
));
512 top
= node
; /* nil */
513 cmm_smp_wmb(); /* write into node before publish */
514 /* make new branch visible to readers */
515 _CMM_STORE_SHARED(rbtree
->root
, prev
);
520 /* update children */
523 assert(!rcu_rbtree_is_nil(rbtree
, node
));
524 set_parent(node
->_left
, get_decay(get_parent(node
->_left
)), IS_LEFT
);
525 set_parent(node
->_right
, get_decay(get_parent(node
->_right
)), IS_RIGHT
);
526 } while ((node
= get_parent(node
)) != top
);
530 * We have to ensure these assumptions are correct for prev/next
533 * with x being a right child, the assumption that:
534 * get_parent(x)->_right == x
535 * or if x is a left child, the assumption that:
536 * get_parent(x)->_left == x
538 * This explains why we have to allocate a vc copy of the node for left_rotate,
539 * right_rotate and transplant operations.
541 * We always ensure that the right/left child and correct parent is set in the
542 * node copies *before* we reparent the children and make the upper-level point
546 /* RCU: copy x and y, atomically point to new versions. GC old. */
547 /* Should be eventually followed by a cmm_smp_wmc() */
549 #ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
552 void left_rotate(struct rcu_rbtree
*rbtree
,
553 struct rcu_rbtree_node
*x
)
555 struct rcu_rbtree_node
*y
, *y_left
;
557 dbg_printf("left rotate %lx\n", (unsigned long) x
->begin
);
562 /* Now operate on new copy, decay old versions */
563 x
= dup_decay_node(rbtree
, x
);
564 y
= dup_decay_node(rbtree
, y
);
565 y_left
= dup_decay_node(rbtree
, y_left
);
567 check_max_end(rbtree
, get_parent(x
));
568 check_max_end(rbtree
, x
);
569 check_max_end(rbtree
, y
);
571 /* Internal node modifications */
572 set_parent(y
, get_parent(x
), get_pos(x
));
573 set_parent(x
, y
, IS_LEFT
);
574 set_left(rbtree
, y
, x
);
575 set_right(rbtree
, x
, y_left
);
577 if (!rcu_rbtree_is_nil(rbtree
, y_left
))
578 set_parent(y_left
, x
, IS_RIGHT
);
581 * We only changed the relative position of x and y wrt their
582 * children, and reparented y (but are keeping the same nodes in
583 * place, so its parent does not need to have end value
586 x
->max_end
= calculate_node_max_end(rbtree
, x
);
587 y
->max_end
= calculate_node_max_end(rbtree
, y
);
589 cmm_smp_wmb(); /* write into node before publish */
591 /* External references update (visible by readers) */
592 if (rcu_rbtree_is_nil(rbtree
, get_parent(y
)))
593 _CMM_STORE_SHARED(rbtree
->root
, y
);
594 else if (get_pos(y
) == IS_LEFT
)
595 _CMM_STORE_SHARED(get_parent(y
)->_left
, y
);
597 _CMM_STORE_SHARED(get_parent(y
)->_right
, y
);
599 /* Point children to new copy (parent only used by updates/next/prev) */
600 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
602 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)),
604 if (!rcu_rbtree_is_nil(rbtree
, y_left
)) {
605 set_parent(y_left
->_right
,
606 get_decay(get_parent(y_left
->_right
)),
607 get_pos(y_left
->_right
));
608 set_parent(y_left
->_left
,
609 get_decay(get_parent(y_left
->_left
)),
610 get_pos(y_left
->_left
));
614 assert(y
== rbtree
->root
|| get_parent(y
)->_left
== y
615 || get_parent(y
)->_right
== y
);
616 assert(x
== rbtree
->root
|| get_parent(x
)->_left
== x
617 || get_parent(x
)->_right
== x
);
618 assert(rcu_rbtree_is_nil(rbtree
, x
->_right
) || get_parent(x
->_right
) == x
);
619 assert(rcu_rbtree_is_nil(rbtree
, x
->_left
) || get_parent(x
->_left
) == x
);
620 assert(rcu_rbtree_is_nil(rbtree
, y
->_right
) || get_parent(y
->_right
) == y
);
621 assert(rcu_rbtree_is_nil(rbtree
, y
->_left
) || get_parent(y
->_left
) == y
);
622 assert(!is_decay(rbtree
->root
));
623 assert(!is_decay(x
));
624 assert(!is_decay(y
));
625 assert(!is_decay(x
->_right
));
626 assert(!is_decay(x
->_left
));
627 assert(!is_decay(y
->_right
));
628 assert(!is_decay(y
->_left
));
629 check_max_end(rbtree
, get_parent(y
));
630 check_max_end(rbtree
, x
);
631 check_max_end(rbtree
, y
);
636 /* non-rcu version */
638 void left_rotate(struct rcu_rbtree
*rbtree
,
639 struct rcu_rbtree_node
*x
)
641 struct rcu_rbtree_node
*y
;
645 x
->_right
= y
->_left
;
646 if (!rcu_rbtree_is_nil(rbtree
, y
->_left
))
647 set_parent(y
->_left
, x
, IS_RIGHT
);
648 set_parent(y
, get_parent(x
), get_pos(x
));
649 if (rcu_rbtree_is_nil(rbtree
, get_parent(x
)))
651 else if (x
== get_parent(x
)->_left
) {
652 get_parent(x
)->_left
= y
;
654 get_parent(x
)->_right
= y
;
657 set_parent(x
, y
, IS_LEFT
);
663 #ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
665 void right_rotate(struct rcu_rbtree
*rbtree
,
666 struct rcu_rbtree_node
*x
)
668 struct rcu_rbtree_node
*y
, *y_right
;
670 dbg_printf("right rotate %lx\n", (unsigned long) x
->begin
);
675 /* Now operate on new copy, decay old versions */
676 x
= dup_decay_node(rbtree
, x
);
677 y
= dup_decay_node(rbtree
, y
);
678 y_right
= dup_decay_node(rbtree
, y_right
);
680 check_max_end(rbtree
, get_parent(x
));
681 check_max_end(rbtree
, x
);
682 check_max_end(rbtree
, y
);
684 /* Internal node modifications */
685 set_parent(y
, get_parent(x
), get_pos(x
));
686 set_parent(x
, y
, IS_RIGHT
);
687 set_right(rbtree
, y
, x
);
688 set_left(rbtree
, x
, y_right
);
690 if (!rcu_rbtree_is_nil(rbtree
, y_right
))
691 set_parent(y_right
, x
, IS_LEFT
);
694 * We only changed the relative position of x and y wrt their
695 * children, and reparented y (but are keeping the same nodes in
696 * place, so its parent does not need to have end value
699 x
->max_end
= calculate_node_max_end(rbtree
, x
);
700 y
->max_end
= calculate_node_max_end(rbtree
, y
);
702 cmm_smp_wmb(); /* write into node before publish */
704 /* External references update (visible by readers) */
705 if (rcu_rbtree_is_nil(rbtree
, get_parent(y
)))
706 _CMM_STORE_SHARED(rbtree
->root
, y
);
707 else if (get_pos(y
) == IS_RIGHT
)
708 _CMM_STORE_SHARED(get_parent(y
)->_right
, y
);
710 _CMM_STORE_SHARED(get_parent(y
)->_left
, y
);
712 /* Point children to new copy (parent only used by updates/next/prev) */
713 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
715 set_parent(y
->_left
, get_decay(get_parent(y
->_left
)),
717 if (!rcu_rbtree_is_nil(rbtree
, y_right
)) {
718 set_parent(y_right
->_left
,
719 get_decay(get_parent(y_right
->_left
)),
720 get_pos(y_right
->_left
));
721 set_parent(y_right
->_right
,
722 get_decay(get_parent(y_right
->_right
)),
723 get_pos(y_right
->_right
));
727 assert(y
== rbtree
->root
|| get_parent(y
)->_right
== y
728 || get_parent(y
)->_left
== y
);
729 assert(x
== rbtree
->root
|| get_parent(x
)->_right
== x
730 || get_parent(x
)->_left
== x
);
731 assert(rcu_rbtree_is_nil(rbtree
, x
->_left
) || get_parent(x
->_left
) == x
);
732 assert(rcu_rbtree_is_nil(rbtree
, x
->_right
) || get_parent(x
->_right
) == x
);
733 assert(rcu_rbtree_is_nil(rbtree
, y
->_left
) || get_parent(y
->_left
) == y
);
734 assert(rcu_rbtree_is_nil(rbtree
, y
->_right
) || get_parent(y
->_right
) == y
);
735 assert(!is_decay(rbtree
->root
));
736 assert(!is_decay(x
));
737 assert(!is_decay(y
));
738 assert(!is_decay(x
->_left
));
739 assert(!is_decay(x
->_right
));
740 assert(!is_decay(y
->_left
));
741 assert(!is_decay(y
->_right
));
742 check_max_end(rbtree
, x
);
743 check_max_end(rbtree
, y
);
744 check_max_end(rbtree
, get_parent(y
));
749 /* non-rcu version */
751 void right_rotate(struct rcu_rbtree
*rbtree
,
752 struct rcu_rbtree_node
*x
)
754 struct rcu_rbtree_node
*y
;
758 x
->_left
= y
->_right
;
759 if (!rcu_rbtree_is_nil(rbtree
, y
->_right
))
760 set_parent(y
->_right
, x
, IS_LEFT
);
761 set_parent(y
, get_parent(x
), get_pos(x
));
762 if (rcu_rbtree_is_nil(rbtree
, get_parent(x
)))
764 else if (x
== get_parent(x
)->_right
) {
765 get_parent(x
)->_right
= y
;
767 get_parent(x
)->_left
= y
;
770 set_parent(x
, y
, IS_RIGHT
);
776 static void rcu_rbtree_insert_fixup(struct rcu_rbtree
*rbtree
,
777 struct rcu_rbtree_node
*z
)
779 struct rcu_rbtree_node
*y
;
781 dbg_printf("insert fixup %p\n", z
->begin
);
782 assert(!is_decay(rbtree
->root
));
784 while (get_parent(z
)->color
== COLOR_RED
) {
785 if (get_parent(z
) == get_parent(get_parent(z
))->_left
) {
786 y
= get_parent(get_parent(z
))->_right
;
787 if (y
->color
== COLOR_RED
) {
788 get_parent(z
)->color
= COLOR_BLACK
;
789 y
->color
= COLOR_BLACK
;
790 get_parent(get_parent(z
))->color
= COLOR_RED
;
791 z
= get_parent(get_parent(z
));
793 if (z
== get_parent(z
)->_right
) {
795 left_rotate(rbtree
, z
);
797 assert(!is_decay(rbtree
->root
));
799 get_parent(z
)->color
= COLOR_BLACK
;
800 get_parent(get_parent(z
))->color
= COLOR_RED
;
801 assert(!is_decay(z
));
802 assert(!is_decay(get_parent(z
)));
803 assert(!is_decay(get_parent(get_parent(z
))));
804 right_rotate(rbtree
, get_parent(get_parent(z
)));
805 assert(!is_decay(z
));
806 assert(!is_decay(rbtree
->root
));
809 y
= get_parent(get_parent(z
))->_left
;
810 if (y
->color
== COLOR_RED
) {
811 get_parent(z
)->color
= COLOR_BLACK
;
812 y
->color
= COLOR_BLACK
;
813 get_parent(get_parent(z
))->color
= COLOR_RED
;
814 z
= get_parent(get_parent(z
));
816 if (z
== get_parent(z
)->_left
) {
818 right_rotate(rbtree
, z
);
820 assert(!is_decay(rbtree
->root
));
822 get_parent(z
)->color
= COLOR_BLACK
;
823 get_parent(get_parent(z
))->color
= COLOR_RED
;
824 left_rotate(rbtree
, get_parent(get_parent(z
)));
825 assert(!is_decay(z
));
826 assert(!is_decay(rbtree
->root
));
830 rbtree
->root
->color
= COLOR_BLACK
;
834 * rcu_rbtree_insert - Insert a node in the RCU rbtree
836 * Returns 0 on success, or < 0 on error.
838 int rcu_rbtree_insert(struct rcu_rbtree
*rbtree
,
839 struct rcu_rbtree_node
*z
)
841 struct rcu_rbtree_node
*x
, *y
;
843 dbg_printf("insert %p\n", z
->begin
);
844 assert(!is_decay(rbtree
->root
));
846 y
= make_nil(rbtree
);
848 while (!rcu_rbtree_is_nil(rbtree
, x
)) {
850 if (rbtree
->comp(z
->begin
, x
->begin
) < 0)
856 z
->_left
= make_nil(rbtree
);
857 z
->_right
= make_nil(rbtree
);
858 z
->color
= COLOR_RED
;
859 z
->decay_next
= NULL
;
862 if (rcu_rbtree_is_nil(rbtree
, y
)) {
863 set_parent(z
, y
, IS_RIGHT
); /* pos arbitrary for root node */
865 * Order stores to z (children/parents) before stores
866 * that will make it visible to the rest of the tree.
869 _CMM_STORE_SHARED(rbtree
->root
, z
);
870 } else if (rbtree
->comp(z
->begin
, y
->begin
) < 0) {
871 y
= dup_decay_node(rbtree
, y
);
872 set_parent(z
, y
, IS_LEFT
);
873 if (get_pos(z
) == IS_LEFT
)
874 _CMM_STORE_SHARED(y
->_left
, z
);
876 _CMM_STORE_SHARED(y
->_right
, z
);
877 populate_node_end(rbtree
, y
, 1, NULL
);
879 y
= dup_decay_node(rbtree
, y
);
880 set_parent(z
, y
, IS_RIGHT
);
881 if (get_pos(z
) == IS_LEFT
)
882 _CMM_STORE_SHARED(y
->_left
, z
);
884 _CMM_STORE_SHARED(y
->_right
, z
);
885 populate_node_end(rbtree
, y
, 1, NULL
);
887 rcu_rbtree_insert_fixup(rbtree
, z
);
889 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
893 check_max_end(rbtree
, z
);
894 check_max_end(rbtree
, y
);
900 * Transplant v into u position.
903 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
906 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
907 struct rcu_rbtree_node
*u
,
908 struct rcu_rbtree_node
*v
,
909 unsigned int copy_parents
,
910 struct rcu_rbtree_node
*stop
)
912 dbg_printf("transplant %p\n", v
->begin
);
914 if (!rcu_rbtree_is_nil(rbtree
, v
))
915 v
= dup_decay_node(rbtree
, v
);
917 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
))) {
918 /* pos is arbitrary for root node */
919 set_parent(v
, get_parent(u
), IS_RIGHT
);
920 cmm_smp_wmb(); /* write into node before publish */
921 _CMM_STORE_SHARED(rbtree
->root
, v
);
923 struct rcu_rbtree_node
*vp
;
927 vp
= dup_decay_node(rbtree
, vp
);
928 set_parent(v
, vp
, get_pos(u
));
929 if (get_pos(v
) == IS_LEFT
)
930 _CMM_STORE_SHARED(vp
->_left
, v
);
932 _CMM_STORE_SHARED(vp
->_right
, v
);
933 populate_node_end(rbtree
, vp
, copy_parents
, stop
);
934 check_max_end(rbtree
, vp
);
937 /* Point children to new copy (parent only used by updates/next/prev) */
938 if (!rcu_rbtree_is_nil(rbtree
, v
)) {
939 set_parent(v
->_right
, get_decay(get_parent(v
->_right
)),
941 set_parent(v
->_left
, get_decay(get_parent(v
->_left
)),
944 assert(!is_decay(rbtree
->root
));
945 check_max_end(rbtree
, v
);
950 /* Non-RCU version */
952 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
953 struct rcu_rbtree_node
*u
,
954 struct rcu_rbtree_node
*v
,
955 unsigned int copy_parents
,
956 struct rcu_rbtree_node
*stop
)
958 dbg_printf("transplant %p\n", v
->begin
);
961 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
)))
963 else if (u
== get_parent(u
)->_left
)
964 get_parent(u
)->_left
= v
;
966 get_parent(u
)->_right
= v
;
967 set_parent(v
, get_parent(u
), get_pos(u
));
973 static void rcu_rbtree_remove_fixup(struct rcu_rbtree
*rbtree
,
974 struct rcu_rbtree_node
*x
)
976 dbg_printf("remove fixup %p\n", x
->begin
);
978 while (x
!= rbtree
->root
&& x
->color
== COLOR_BLACK
) {
979 assert(!is_decay(get_parent(x
)));
980 assert(!is_decay(get_parent(x
)->_left
));
981 if (x
== get_parent(x
)->_left
) {
982 struct rcu_rbtree_node
*w
;
984 w
= get_parent(x
)->_right
;
986 if (w
->color
== COLOR_RED
) {
987 w
->color
= COLOR_BLACK
;
988 get_parent(x
)->color
= COLOR_RED
;
989 left_rotate(rbtree
, get_parent(x
));
991 assert(!is_decay(rbtree
->root
));
992 w
= get_parent(x
)->_right
;
994 if (w
->_left
->color
== COLOR_BLACK
995 && w
->_right
->color
== COLOR_BLACK
) {
996 w
->color
= COLOR_RED
;
998 assert(!is_decay(rbtree
->root
));
999 assert(!is_decay(x
));
1001 if (w
->_right
->color
== COLOR_BLACK
) {
1002 w
->_left
->color
= COLOR_BLACK
;
1003 w
->color
= COLOR_RED
;
1004 right_rotate(rbtree
, w
);
1005 assert(!is_decay(rbtree
->root
));
1007 w
= get_parent(x
)->_right
;
1009 w
->color
= get_parent(x
)->color
;
1010 get_parent(x
)->color
= COLOR_BLACK
;
1011 w
->_right
->color
= COLOR_BLACK
;
1012 left_rotate(rbtree
, get_parent(x
));
1013 assert(!is_decay(rbtree
->root
));
1017 struct rcu_rbtree_node
*w
;
1019 w
= get_parent(x
)->_left
;
1021 if (w
->color
== COLOR_RED
) {
1022 w
->color
= COLOR_BLACK
;
1023 get_parent(x
)->color
= COLOR_RED
;
1024 right_rotate(rbtree
, get_parent(x
));
1025 assert(!is_decay(rbtree
->root
));
1027 w
= get_parent(x
)->_left
;
1029 if (w
->_right
->color
== COLOR_BLACK
1030 && w
->_left
->color
== COLOR_BLACK
) {
1031 w
->color
= COLOR_RED
;
1033 assert(!is_decay(rbtree
->root
));
1034 assert(!is_decay(x
));
1036 if (w
->_left
->color
== COLOR_BLACK
) {
1037 w
->_right
->color
= COLOR_BLACK
;
1038 w
->color
= COLOR_RED
;
1039 left_rotate(rbtree
, w
);
1040 assert(!is_decay(rbtree
->root
));
1042 w
= get_parent(x
)->_left
;
1044 w
->color
= get_parent(x
)->color
;
1045 get_parent(x
)->color
= COLOR_BLACK
;
1046 w
->_left
->color
= COLOR_BLACK
;
1047 right_rotate(rbtree
, get_parent(x
));
1048 assert(!is_decay(rbtree
->root
));
1053 x
->color
= COLOR_BLACK
;
1057 * Delete z. All non-copied children left/right positions are unchanged.
1060 void rcu_rbtree_remove_nonil(struct rcu_rbtree
*rbtree
,
1061 struct rcu_rbtree_node
*z
,
1062 struct rcu_rbtree_node
*y
)
1064 struct rcu_rbtree_node
*x
;
1066 dbg_printf("remove nonil %p\n", z
->begin
);
1069 assert(!is_decay(z
));
1070 assert(!is_decay(y
));
1071 assert(!is_decay(y
->_right
));
1072 assert(!is_decay(get_parent(y
)));
1074 assert(!is_decay(x
));
1075 if (get_parent(y
) == z
) {
1076 y
= dup_decay_node(rbtree
, y
);
1077 set_parent(x
, y
, get_pos(x
)); /* parent for nil */
1078 /* y is z's right node */
1079 set_left(rbtree
, y
, z
->_left
);
1080 y
->max_end
= calculate_node_max_end(rbtree
, y
);
1081 rcu_rbtree_transplant(rbtree
, z
, y
, 1, NULL
);
1083 struct rcu_rbtree_node
*oy_right
, *z_right
;
1086 * Need to make sure y is always visible by readers.
1088 y
= rcu_rbtree_min_dup_decay(rbtree
, z
->_right
, &z_right
);
1089 assert(!is_decay(y
));
1090 assert(!is_decay(z
));
1091 oy_right
= y
->_right
;
1094 * The max child begin of z_right does not change, because
1095 * we're only changing its left children.
1097 y
->_right
= z_right
;
1098 set_parent(y
->_right
, y
, IS_RIGHT
);
1099 assert(!is_decay(z
->_left
));
1100 y
->_left
= z
->_left
;
1101 assert(!is_decay(oy_right
));
1103 * Transplant of oy_right to old y's location will only
1104 * trigger a "end" value update of the already copied branch
1105 * (which is not visible yet). We are transplanting
1106 * oy_right as a left child of old y's parent, so the
1107 * min values update propagated upward necessarily stops
1110 rcu_rbtree_transplant(rbtree
, y
, oy_right
, 0, y
);
1111 y
->max_end
= calculate_node_max_end(rbtree
, y
);
1112 rcu_rbtree_transplant(rbtree
, z
, y
, 1, NULL
);
1113 /* Update children */
1114 (void) rcu_rbtree_min_update_decay(rbtree
, y
->_right
);
1117 assert(!is_decay(z
));
1118 assert(!is_decay(z
->_left
));
1119 y
->color
= z
->color
;
1120 set_parent(y
->_left
, y
, IS_LEFT
);
1121 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)), IS_RIGHT
);
1122 assert(!is_decay(y
->_left
));
1123 assert(!is_decay(y
->_right
));
1126 int rcu_rbtree_remove(struct rcu_rbtree
*rbtree
,
1127 struct rcu_rbtree_node
*z
)
1129 struct rcu_rbtree_node
*x
, *y
;
1130 unsigned int y_original_color
;
1132 assert(!is_decay(rbtree
->root
));
1133 dbg_printf("remove %p\n", z
->begin
);
1136 assert(!is_decay(z
));
1138 y_original_color
= y
->color
;
1140 if (rcu_rbtree_is_nil(rbtree
, z
->_left
)) {
1141 rcu_rbtree_transplant(rbtree
, z
, z
->_right
, 1, NULL
);
1142 assert(!is_decay(z
));
1143 x
= get_decay(z
->_right
);
1145 } else if (rcu_rbtree_is_nil(rbtree
, z
->_right
)) {
1146 rcu_rbtree_transplant(rbtree
, z
, z
->_left
, 1, NULL
);
1147 assert(!is_decay(z
));
1148 x
= get_decay(z
->_left
);
1151 y
= rcu_rbtree_min(rbtree
, z
->_right
);
1152 assert(!is_decay(y
));
1153 y_original_color
= y
->color
;
1155 rcu_rbtree_remove_nonil(rbtree
, z
, y
);
1159 if (y_original_color
== COLOR_BLACK
)
1160 rcu_rbtree_remove_fixup(rbtree
, x
);
1162 check_max_end(rbtree
, x
);
1163 check_max_end(rbtree
, get_decay(y
));
1165 * Commit all _CMM_STORE_SHARED().