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("{ 0x%lX p:%lX r:%lX l:%lX %s %s %s} ",
197 (unsigned long)node
->key
,
198 (unsigned long) get_parent(node
)->key
,
199 (unsigned long) node
->_right
->key
,
200 (unsigned long) node
->_left
->key
,
201 node
->color
? "red" : "black",
202 get_pos(node
) ? "right" : "left",
203 rcu_rbtree_is_nil(rbtree
, node
) ? "nil" : "");
204 node
= rcu_rbtree_next(rbtree
, node
);
210 void show_tree(struct rcu_rbtree
*rbtree
)
216 struct rcu_rbtree_node
*make_nil(struct rcu_rbtree
*rbtree
)
218 return &rbtree
->nil_node
;
222 * Iterative rbtree search.
224 struct rcu_rbtree_node
*rcu_rbtree_search(struct rcu_rbtree
*rbtree
,
225 struct rcu_rbtree_node
*x
,
228 x
= rcu_dereference(x
);
231 while (!rcu_rbtree_is_nil(rbtree
, x
) && (comp
= rbtree
->comp(k
, x
->key
)) != 0) {
234 x
= rcu_dereference(x
->_left
);
236 x
= rcu_dereference(x
->_right
);
242 struct rcu_rbtree_node
*rcu_rbtree_min_dup_decay(struct rcu_rbtree
*rbtree
,
243 struct rcu_rbtree_node
*x
,
244 struct rcu_rbtree_node
**zr
)
246 struct rcu_rbtree_node
*xl
;
248 x
= rcu_dereference(x
);
250 if (rcu_rbtree_is_nil(rbtree
, x
)) {
254 *zr
= x
= dup_decay_node(rbtree
, x
);
256 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
))) {
257 x
= dup_decay_node(rbtree
, xl
);
258 set_parent(x
, get_decay(get_parent(x
)), get_pos(x
));
259 get_parent(x
)->_left
= get_decay(get_parent(x
)->_left
);
265 struct rcu_rbtree_node
*rcu_rbtree_min_update_decay(struct rcu_rbtree
*rbtree
,
266 struct rcu_rbtree_node
*x
)
268 struct rcu_rbtree_node
*xl
;
270 x
= rcu_dereference(x
);
272 if (rcu_rbtree_is_nil(rbtree
, x
))
275 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
277 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
281 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
))) {
283 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
285 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
291 struct rcu_rbtree_node
*rcu_rbtree_min(struct rcu_rbtree
*rbtree
,
292 struct rcu_rbtree_node
*x
)
294 struct rcu_rbtree_node
*xl
;
296 x
= rcu_dereference(x
);
298 if (rcu_rbtree_is_nil(rbtree
, x
))
301 while (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
)))
306 struct rcu_rbtree_node
*rcu_rbtree_max(struct rcu_rbtree
*rbtree
,
307 struct rcu_rbtree_node
*x
)
309 struct rcu_rbtree_node
*xr
;
311 x
= rcu_dereference(x
);
313 if (rcu_rbtree_is_nil(rbtree
, x
))
316 while (!rcu_rbtree_is_nil(rbtree
, xr
= rcu_dereference(x
->_right
)))
323 * Updates should wait for a grace period between update of the
324 * redirect pointer and update of the parent child pointer. This is to make sure
325 * that no reference to the old entry exist.
329 * RCU read lock must be held across the next/prev calls to ensure validity of
332 struct rcu_rbtree_node
*rcu_rbtree_next(struct rcu_rbtree
*rbtree
,
333 struct rcu_rbtree_node
*x
)
335 struct rcu_rbtree_node
*xr
, *y
;
338 x
= rcu_dereference(x
);
340 if (!rcu_rbtree_is_nil(rbtree
, xr
= rcu_dereference(x
->_right
)))
341 return rcu_rbtree_min(rbtree
, xr
);
342 y
= get_parent_and_pos(x
, &x_pos
);
343 while (!rcu_rbtree_is_nil(rbtree
, y
) && x_pos
== IS_RIGHT
) {
345 y
= get_parent_and_pos(y
, &x_pos
);
350 struct rcu_rbtree_node
*rcu_rbtree_prev(struct rcu_rbtree
*rbtree
,
351 struct rcu_rbtree_node
*x
)
353 struct rcu_rbtree_node
*xl
, *y
;
356 x
= rcu_dereference(x
);
358 if (!rcu_rbtree_is_nil(rbtree
, xl
= rcu_dereference(x
->_left
)))
359 return rcu_rbtree_max(rbtree
, xl
);
360 y
= get_parent_and_pos(x
, &x_pos
);
361 while (!rcu_rbtree_is_nil(rbtree
, y
) && x_pos
== IS_LEFT
) {
363 y
= get_parent_and_pos(y
, &x_pos
);
369 * We have to ensure these assumptions are correct for prev/next
372 * with x being a right child, the assumption that:
373 * get_parent(x)->_right == x
374 * or if x is a left child, the assumption that:
375 * get_parent(x)->_left == x
377 * This explains why we have to allocate a vc copy of the node for left_rotate,
378 * right_rotate and transplant operations.
380 * We always ensure that the right/left child and correct parent is set in the
381 * node copies *before* we reparent the children and make the upper-level point
385 /* RCU: copy x and y, atomically point to new versions. GC old. */
386 /* Should be eventually followed by a cmm_smp_wmc() */
388 #ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
391 void left_rotate(struct rcu_rbtree
*rbtree
,
392 struct rcu_rbtree_node
*x
)
394 struct rcu_rbtree_node
*y
, *y_left
;
399 /* Now operate on new copy, decay old versions */
400 x
= dup_decay_node(rbtree
, x
);
401 y
= dup_decay_node(rbtree
, y
);
402 y_left
= dup_decay_node(rbtree
, y_left
);
404 /* Internal node modifications */
405 set_parent(y
, get_parent(x
), get_pos(x
));
406 set_parent(x
, y
, IS_LEFT
);
407 set_left(rbtree
, y
, x
);
408 set_right(rbtree
, x
, y_left
);
410 if (!rcu_rbtree_is_nil(rbtree
, y_left
))
411 set_parent(y_left
, x
, IS_RIGHT
);
413 cmm_smp_wmb(); /* write into node before publish */
415 /* External references update (visible by readers) */
416 if (rcu_rbtree_is_nil(rbtree
, get_parent(y
)))
417 _CMM_STORE_SHARED(rbtree
->root
, y
);
418 else if (get_pos(y
) == IS_LEFT
)
419 _CMM_STORE_SHARED(get_parent(y
)->_left
, y
);
421 _CMM_STORE_SHARED(get_parent(y
)->_right
, y
);
423 /* Point children to new copy (parent only used by updates/next/prev) */
424 set_parent(x
->_left
, get_decay(get_parent(x
->_left
)),
426 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)),
428 if (!rcu_rbtree_is_nil(rbtree
, y_left
)) {
429 set_parent(y_left
->_right
,
430 get_decay(get_parent(y_left
->_right
)),
431 get_pos(y_left
->_right
));
432 set_parent(y_left
->_left
,
433 get_decay(get_parent(y_left
->_left
)),
434 get_pos(y_left
->_left
));
438 assert(y
== rbtree
->root
|| get_parent(y
)->_left
== y
439 || get_parent(y
)->_right
== y
);
440 assert(x
== rbtree
->root
|| get_parent(x
)->_left
== x
441 || get_parent(x
)->_right
== x
);
442 assert(rcu_rbtree_is_nil(rbtree
, x
->_right
) || get_parent(x
->_right
) == x
);
443 assert(rcu_rbtree_is_nil(rbtree
, x
->_left
) || get_parent(x
->_left
) == x
);
444 assert(rcu_rbtree_is_nil(rbtree
, y
->_right
) || get_parent(y
->_right
) == y
);
445 assert(rcu_rbtree_is_nil(rbtree
, y
->_left
) || get_parent(y
->_left
) == y
);
446 assert(!is_decay(rbtree
->root
));
447 assert(!is_decay(x
));
448 assert(!is_decay(y
));
449 assert(!is_decay(x
->_right
));
450 assert(!is_decay(x
->_left
));
451 assert(!is_decay(y
->_right
));
452 assert(!is_decay(y
->_left
));
457 /* non-rcu version */
459 void left_rotate(struct rcu_rbtree
*rbtree
,
460 struct rcu_rbtree_node
*x
)
462 struct rcu_rbtree_node
*y
;
466 x
->_right
= y
->_left
;
467 if (!rcu_rbtree_is_nil(rbtree
, y
->_left
))
468 set_parent(y
->_left
, x
, IS_RIGHT
);
469 set_parent(y
, get_parent(x
), get_pos(x
));
470 if (rcu_rbtree_is_nil(rbtree
, get_parent(x
)))
472 else if (x
== get_parent(x
)->_left
) {
473 get_parent(x
)->_left
= y
;
475 get_parent(x
)->_right
= y
;
478 set_parent(x
, y
, IS_LEFT
);
484 #ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
486 void right_rotate(struct rcu_rbtree
*rbtree
,
487 struct rcu_rbtree_node
*x
)
489 struct rcu_rbtree_node
*y
, *y_right
;
494 /* Now operate on new copy, decay old versions */
495 x
= dup_decay_node(rbtree
, x
);
496 y
= dup_decay_node(rbtree
, y
);
497 y_right
= dup_decay_node(rbtree
, y_right
);
499 /* Internal node modifications */
500 set_parent(y
, get_parent(x
), get_pos(x
));
501 set_parent(x
, y
, IS_RIGHT
);
502 set_right(rbtree
, y
, x
);
503 set_left(rbtree
, x
, y_right
);
505 if (!rcu_rbtree_is_nil(rbtree
, y_right
))
506 set_parent(y_right
, x
, IS_LEFT
);
508 cmm_smp_wmb(); /* write into node before publish */
510 /* External references update (visible by readers) */
511 if (rcu_rbtree_is_nil(rbtree
, get_parent(y
)))
512 _CMM_STORE_SHARED(rbtree
->root
, y
);
513 else if (get_pos(y
) == IS_RIGHT
)
514 _CMM_STORE_SHARED(get_parent(y
)->_right
, y
);
516 _CMM_STORE_SHARED(get_parent(y
)->_left
, y
);
518 /* Point children to new copy (parent only used by updates/next/prev) */
519 set_parent(x
->_right
, get_decay(get_parent(x
->_right
)),
521 set_parent(y
->_left
, get_decay(get_parent(y
->_left
)),
523 if (!rcu_rbtree_is_nil(rbtree
, y_right
)) {
524 set_parent(y_right
->_left
,
525 get_decay(get_parent(y_right
->_left
)),
526 get_pos(y_right
->_left
));
527 set_parent(y_right
->_right
,
528 get_decay(get_parent(y_right
->_right
)),
529 get_pos(y_right
->_right
));
533 assert(y
== rbtree
->root
|| get_parent(y
)->_right
== y
534 || get_parent(y
)->_left
== y
);
535 assert(x
== rbtree
->root
|| get_parent(x
)->_right
== x
536 || get_parent(x
)->_left
== x
);
537 assert(rcu_rbtree_is_nil(rbtree
, x
->_left
) || get_parent(x
->_left
) == x
);
538 assert(rcu_rbtree_is_nil(rbtree
, x
->_right
) || get_parent(x
->_right
) == x
);
539 assert(rcu_rbtree_is_nil(rbtree
, y
->_left
) || get_parent(y
->_left
) == y
);
540 assert(rcu_rbtree_is_nil(rbtree
, y
->_right
) || get_parent(y
->_right
) == y
);
541 assert(!is_decay(rbtree
->root
));
542 assert(!is_decay(x
));
543 assert(!is_decay(y
));
544 assert(!is_decay(x
->_left
));
545 assert(!is_decay(x
->_right
));
546 assert(!is_decay(y
->_left
));
547 assert(!is_decay(y
->_right
));
552 /* non-rcu version */
554 void right_rotate(struct rcu_rbtree
*rbtree
,
555 struct rcu_rbtree_node
*x
)
557 struct rcu_rbtree_node
*y
;
561 x
->_left
= y
->_right
;
562 if (!rcu_rbtree_is_nil(rbtree
, y
->_right
))
563 set_parent(y
->_right
, x
, IS_LEFT
);
564 set_parent(y
, get_parent(x
), get_pos(x
));
565 if (rcu_rbtree_is_nil(rbtree
, get_parent(x
)))
567 else if (x
== get_parent(x
)->_right
) {
568 get_parent(x
)->_right
= y
;
570 get_parent(x
)->_left
= y
;
573 set_parent(x
, y
, IS_RIGHT
);
579 static void rcu_rbtree_insert_fixup(struct rcu_rbtree
*rbtree
,
580 struct rcu_rbtree_node
*z
)
582 struct rcu_rbtree_node
*y
;
584 dbg_printf("insert fixup %p\n", z
->key
);
585 assert(!is_decay(rbtree
->root
));
587 while (get_parent(z
)->color
== COLOR_RED
) {
588 if (get_parent(z
) == get_parent(get_parent(z
))->_left
) {
589 y
= get_parent(get_parent(z
))->_right
;
590 if (y
->color
== COLOR_RED
) {
591 get_parent(z
)->color
= COLOR_BLACK
;
592 y
->color
= COLOR_BLACK
;
593 get_parent(get_parent(z
))->color
= COLOR_RED
;
594 z
= get_parent(get_parent(z
));
596 if (z
== get_parent(z
)->_right
) {
598 left_rotate(rbtree
, z
);
600 assert(!is_decay(rbtree
->root
));
602 get_parent(z
)->color
= COLOR_BLACK
;
603 get_parent(get_parent(z
))->color
= COLOR_RED
;
604 assert(!is_decay(z
));
605 assert(!is_decay(get_parent(z
)));
606 assert(!is_decay(get_parent(get_parent(z
))));
607 right_rotate(rbtree
, get_parent(get_parent(z
)));
608 assert(!is_decay(z
));
609 assert(!is_decay(rbtree
->root
));
612 y
= get_parent(get_parent(z
))->_left
;
613 if (y
->color
== COLOR_RED
) {
614 get_parent(z
)->color
= COLOR_BLACK
;
615 y
->color
= COLOR_BLACK
;
616 get_parent(get_parent(z
))->color
= COLOR_RED
;
617 z
= get_parent(get_parent(z
));
619 if (z
== get_parent(z
)->_left
) {
621 right_rotate(rbtree
, z
);
623 assert(!is_decay(rbtree
->root
));
625 get_parent(z
)->color
= COLOR_BLACK
;
626 get_parent(get_parent(z
))->color
= COLOR_RED
;
627 left_rotate(rbtree
, get_parent(get_parent(z
)));
628 assert(!is_decay(z
));
629 assert(!is_decay(rbtree
->root
));
633 rbtree
->root
->color
= COLOR_BLACK
;
637 * rcu_rbtree_insert - Insert a node in the RCU rbtree
639 * Returns 0 on success, or < 0 on error.
641 int rcu_rbtree_insert(struct rcu_rbtree
*rbtree
,
642 struct rcu_rbtree_node
*z
)
644 struct rcu_rbtree_node
*x
, *y
;
646 dbg_printf("insert %p\n", z
->key
);
647 assert(!is_decay(rbtree
->root
));
649 y
= make_nil(rbtree
);
651 while (!rcu_rbtree_is_nil(rbtree
, x
)) {
653 if (rbtree
->comp(z
->key
, x
->key
) < 0)
659 z
->_left
= make_nil(rbtree
);
660 z
->_right
= make_nil(rbtree
);
661 z
->color
= COLOR_RED
;
662 z
->decay_next
= NULL
;
664 if (rcu_rbtree_is_nil(rbtree
, y
))
665 set_parent(z
, y
, IS_RIGHT
); /* pos arbitrary for root node */
666 else if (rbtree
->comp(z
->key
, y
->key
) < 0)
667 set_parent(z
, y
, IS_LEFT
);
669 set_parent(z
, y
, IS_RIGHT
);
671 if (rcu_rbtree_is_nil(rbtree
, y
)) {
673 * Order stores to z (children/parents) before stores
674 * that will make it visible to the rest of the tree.
677 _CMM_STORE_SHARED(rbtree
->root
, z
);
678 } else if (rbtree
->comp(z
->key
, y
->key
) < 0) {
679 set_left(rbtree
, y
, z
);
681 * Order stores to z (children/parents) before stores
682 * that will make it visible to the rest of the tree.
685 if (rcu_rbtree_is_nil(rbtree
, y
))
686 _CMM_STORE_SHARED(rbtree
->root
, z
);
687 else if (get_pos(z
) == IS_LEFT
)
688 _CMM_STORE_SHARED(y
->_left
, z
);
690 _CMM_STORE_SHARED(y
->_right
, z
);
692 set_right(rbtree
, y
, z
);
694 * Order stores to z (children/parents) before stores
695 * that will make it visible to the rest of the tree.
698 if (rcu_rbtree_is_nil(rbtree
, y
))
699 _CMM_STORE_SHARED(rbtree
->root
, z
);
700 else if (get_pos(z
) == IS_LEFT
)
701 _CMM_STORE_SHARED(y
->_left
, z
);
703 _CMM_STORE_SHARED(y
->_right
, z
);
705 rcu_rbtree_insert_fixup(rbtree
, z
);
707 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
716 * Transplant v into u position.
719 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
722 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
723 struct rcu_rbtree_node
*u
,
724 struct rcu_rbtree_node
*v
,
725 unsigned int copy_parents
)
727 dbg_printf("transplant %p\n", v
->key
);
729 if (!rcu_rbtree_is_nil(rbtree
, v
))
730 v
= dup_decay_node(rbtree
, v
);
732 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
))) {
733 /* pos is arbitrary for root node */
734 set_parent(v
, get_parent(u
), IS_RIGHT
);
735 cmm_smp_wmb(); /* write into node before publish */
736 _CMM_STORE_SHARED(rbtree
->root
, v
);
738 set_parent(v
, get_parent(u
), get_pos(u
));
740 if (get_pos(u
) == IS_LEFT
)
741 set_left(rbtree
, get_parent(u
), v
);
743 set_right(rbtree
, get_parent(u
), v
);
745 cmm_smp_wmb(); /* write into node before publish */
747 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
)))
748 _CMM_STORE_SHARED(rbtree
->root
, v
);
749 else if (get_pos(u
) == IS_LEFT
)
750 _CMM_STORE_SHARED(get_parent(u
)->_left
, v
);
752 _CMM_STORE_SHARED(get_parent(u
)->_right
, v
);
755 /* Point children to new copy (parent only used by updates/next/prev) */
756 if (!rcu_rbtree_is_nil(rbtree
, v
)) {
757 set_parent(v
->_right
, get_decay(get_parent(v
->_right
)),
759 set_parent(v
->_left
, get_decay(get_parent(v
->_left
)),
762 assert(!is_decay(rbtree
->root
));
767 /* Non-RCU version */
769 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
770 struct rcu_rbtree_node
*u
,
771 struct rcu_rbtree_node
*v
,
772 unsigned int copy_parents
)
774 dbg_printf("transplant %p\n", v
->key
);
777 if (rcu_rbtree_is_nil(rbtree
, get_parent(u
)))
779 else if (u
== get_parent(u
)->_left
)
780 get_parent(u
)->_left
= v
;
782 get_parent(u
)->_right
= v
;
783 set_parent(v
, get_parent(u
), get_pos(u
));
789 static void rcu_rbtree_remove_fixup(struct rcu_rbtree
*rbtree
,
790 struct rcu_rbtree_node
*x
)
792 dbg_printf("remove fixup %p\n", x
->key
);
794 while (x
!= rbtree
->root
&& x
->color
== COLOR_BLACK
) {
795 assert(!is_decay(get_parent(x
)));
796 assert(!is_decay(get_parent(x
)->_left
));
797 if (x
== get_parent(x
)->_left
) {
798 struct rcu_rbtree_node
*w
;
800 w
= get_parent(x
)->_right
;
802 if (w
->color
== COLOR_RED
) {
803 w
->color
= COLOR_BLACK
;
804 get_parent(x
)->color
= COLOR_RED
;
805 left_rotate(rbtree
, get_parent(x
));
807 assert(!is_decay(rbtree
->root
));
808 w
= get_parent(x
)->_right
;
810 if (w
->_left
->color
== COLOR_BLACK
811 && w
->_right
->color
== COLOR_BLACK
) {
812 w
->color
= COLOR_RED
;
814 assert(!is_decay(rbtree
->root
));
815 assert(!is_decay(x
));
817 if (w
->_right
->color
== COLOR_BLACK
) {
818 w
->_left
->color
= COLOR_BLACK
;
819 w
->color
= COLOR_RED
;
820 right_rotate(rbtree
, w
);
821 assert(!is_decay(rbtree
->root
));
823 w
= get_parent(x
)->_right
;
825 w
->color
= get_parent(x
)->color
;
826 get_parent(x
)->color
= COLOR_BLACK
;
827 w
->_right
->color
= COLOR_BLACK
;
828 left_rotate(rbtree
, get_parent(x
));
829 assert(!is_decay(rbtree
->root
));
833 struct rcu_rbtree_node
*w
;
835 w
= get_parent(x
)->_left
;
837 if (w
->color
== COLOR_RED
) {
838 w
->color
= COLOR_BLACK
;
839 get_parent(x
)->color
= COLOR_RED
;
840 right_rotate(rbtree
, get_parent(x
));
841 assert(!is_decay(rbtree
->root
));
843 w
= get_parent(x
)->_left
;
845 if (w
->_right
->color
== COLOR_BLACK
846 && w
->_left
->color
== COLOR_BLACK
) {
847 w
->color
= COLOR_RED
;
849 assert(!is_decay(rbtree
->root
));
850 assert(!is_decay(x
));
852 if (w
->_left
->color
== COLOR_BLACK
) {
853 w
->_right
->color
= COLOR_BLACK
;
854 w
->color
= COLOR_RED
;
855 left_rotate(rbtree
, w
);
856 assert(!is_decay(rbtree
->root
));
858 w
= get_parent(x
)->_left
;
860 w
->color
= get_parent(x
)->color
;
861 get_parent(x
)->color
= COLOR_BLACK
;
862 w
->_left
->color
= COLOR_BLACK
;
863 right_rotate(rbtree
, get_parent(x
));
864 assert(!is_decay(rbtree
->root
));
869 x
->color
= COLOR_BLACK
;
873 * Delete z. All non-copied children left/right positions are unchanged.
876 void rcu_rbtree_remove_nonil(struct rcu_rbtree
*rbtree
,
877 struct rcu_rbtree_node
*z
,
878 struct rcu_rbtree_node
*y
)
880 struct rcu_rbtree_node
*x
;
882 dbg_printf("remove nonil %p\n", z
->key
);
885 assert(!is_decay(z
));
886 assert(!is_decay(y
));
887 assert(!is_decay(y
->_right
));
888 assert(!is_decay(get_parent(y
)));
890 assert(!is_decay(x
));
891 if (get_parent(y
) == z
) {
892 y
= dup_decay_node(rbtree
, y
);
893 set_parent(x
, y
, get_pos(x
)); /* parent for nil */
894 /* y is z's right node: set left will just update y */
895 set_left(rbtree
, y
, z
->_left
);
896 rcu_rbtree_transplant(rbtree
, z
, y
, 1);
898 struct rcu_rbtree_node
*oy_right
, *z_right
;
901 * Need to make sure y is always visible by readers.
903 y
= rcu_rbtree_min_dup_decay(rbtree
, z
->_right
, &z_right
);
904 assert(!is_decay(y
));
905 assert(!is_decay(z
));
906 oy_right
= y
->_right
;
909 * The max child key of z_right does not change, because
910 * we're only changing its left children.
913 set_parent(y
->_right
, y
, IS_RIGHT
);
914 assert(!is_decay(z
->_left
));
916 assert(!is_decay(oy_right
));
918 * Transplant of oy_right to old y's location will only
919 * trigger a min/max update of the already copied branch
920 * (which is not visible yet). We are transplanting
921 * oy_right as a left child of old y's parent, so the
922 * min values update propagated upward necessarily stops
925 rcu_rbtree_transplant(rbtree
, y
, oy_right
, 0);
926 rcu_rbtree_transplant(rbtree
, z
, y
, 1);
927 /* Update children */
928 (void) rcu_rbtree_min_update_decay(rbtree
, y
->_right
);
931 assert(!is_decay(z
));
932 assert(!is_decay(z
->_left
));
934 set_parent(y
->_left
, y
, IS_LEFT
);
935 set_parent(y
->_right
, get_decay(get_parent(y
->_right
)), IS_RIGHT
);
936 assert(!is_decay(y
->_left
));
937 assert(!is_decay(y
->_right
));
940 int rcu_rbtree_remove(struct rcu_rbtree
*rbtree
,
941 struct rcu_rbtree_node
*z
)
943 struct rcu_rbtree_node
*x
, *y
;
944 unsigned int y_original_color
;
946 assert(!is_decay(rbtree
->root
));
947 dbg_printf("remove %p\n", z
->key
);
950 assert(!is_decay(z
));
952 y_original_color
= y
->color
;
954 if (rcu_rbtree_is_nil(rbtree
, z
->_left
)) {
955 rcu_rbtree_transplant(rbtree
, z
, z
->_right
, 1);
956 assert(!is_decay(z
));
957 x
= get_decay(z
->_right
);
959 } else if (rcu_rbtree_is_nil(rbtree
, z
->_right
)) {
960 rcu_rbtree_transplant(rbtree
, z
, z
->_left
, 1);
961 assert(!is_decay(z
));
962 x
= get_decay(z
->_left
);
965 y
= rcu_rbtree_min(rbtree
, z
->_right
);
966 assert(!is_decay(y
));
967 y_original_color
= y
->color
;
969 rcu_rbtree_remove_nonil(rbtree
, z
, y
);
973 if (y_original_color
== COLOR_BLACK
)
974 rcu_rbtree_remove_fixup(rbtree
, x
);
977 * Commit all _CMM_STORE_SHARED().