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.
38 #include <urcu/rcurbtree.h>
39 #include <urcu-pointer.h>
40 #include <urcu-call-rcu.h>
45 #define dbg_printf(args...) printf(args)
47 #define dbg_printf(args...)
51 * Undefine this to enable the non-RCU rotate and transplant functions
54 #define RBTREE_RCU_SUPPORT_ROTATE
55 #define RBTREE_RCU_SUPPORT_TRANSPLANT
58 void set_decay(struct rcu_rbtree_node
*x
, struct rcu_rbtree_node
*xc
)
64 struct rcu_rbtree_node
*get_decay(struct rcu_rbtree_node
*x
)
72 struct rcu_rbtree_node
*is_decay(struct rcu_rbtree_node
*x
)
78 struct rcu_rbtree_node
*dup_decay_node(struct rcu_rbtree
*rbtree
,
79 struct rcu_rbtree_node
*x
)
81 struct rcu_rbtree_node
*xc
;
83 if (rcu_rbtree_is_nil(x
))
86 xc
= rbtree
->rballoc();
87 memcpy(xc
, x
, sizeof(struct rcu_rbtree_node
));
88 xc
->decay_next
= NULL
;
90 call_rcu(&x
->head
, rbtree
->rbfree
);
96 * Deal with memory allocation errors.
97 * Can be ensured by reserving a pool of memory entries before doing the
98 * insertion, which will have to be function of number of
99 * transplantations/rotations required for the operation.
103 void show_tree(struct rcu_rbtree
*rbtree
)
105 struct rcu_rbtree_node
*node
;
107 node
= rcu_rbtree_min(rbtree
, rbtree
->root
);
108 while (!rcu_rbtree_is_nil(node
)) {
109 assert(!is_decay(node
));
110 printf("{ 0x%lX p:%lX r:%lX l:%lX %s %s %s} ",
111 (unsigned long)node
->key
,
112 (unsigned long) node
->p
->key
,
113 (unsigned long) node
->right
->key
,
114 (unsigned long) node
->left
->key
,
115 node
->color
? "red" : "black",
116 node
->pos
? "right" : "left",
117 node
->nil
? "nil" : "");
118 node
= rcu_rbtree_next(rbtree
, node
);
124 struct rcu_rbtree_node
*make_nil(struct rcu_rbtree
*rbtree
)
126 return &rbtree
->nil_node
;
130 * Iterative rbtree search.
132 struct rcu_rbtree_node
* rcu_rbtree_search(struct rcu_rbtree
*rbtree
,
133 struct rcu_rbtree_node
*x
,
136 x
= rcu_dereference(x
);
138 while (!rcu_rbtree_is_nil(x
) && k
!= x
->key
) {
139 if (rbtree
->comp(k
, x
->key
) < 0)
140 x
= rcu_dereference(x
->left
);
142 x
= rcu_dereference(x
->right
);
147 struct rcu_rbtree_node
*rcu_rbtree_min(struct rcu_rbtree
*rbtree
,
148 struct rcu_rbtree_node
*x
)
150 struct rcu_rbtree_node
*xl
;
152 x
= rcu_dereference(x
);
154 if (rcu_rbtree_is_nil(x
))
157 while (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->left
)))
162 struct rcu_rbtree_node
*rcu_rbtree_max(struct rcu_rbtree
*rbtree
,
163 struct rcu_rbtree_node
*x
)
165 struct rcu_rbtree_node
*xr
;
167 x
= rcu_dereference(x
);
169 if (rcu_rbtree_is_nil(x
))
172 while (!rcu_rbtree_is_nil(xr
= rcu_dereference(x
->right
)))
179 * Updates should wait for a grace period between update of the
180 * redirect pointer and update of the parent child pointer. This is to make sure
181 * that no reference to the old entry exist.
185 * next and prev need to have mutex held to ensure that parent pointer is
188 struct rcu_rbtree_node
*rcu_rbtree_next(struct rcu_rbtree
*rbtree
,
189 struct rcu_rbtree_node
*x
)
191 struct rcu_rbtree_node
*xr
, *y
;
193 x
= rcu_dereference(x
);
195 if (!rcu_rbtree_is_nil(xr
= rcu_dereference(x
->right
)))
196 return rcu_rbtree_min(rbtree
, xr
);
197 y
= rcu_dereference(x
->p
);
198 while (!rcu_rbtree_is_nil(y
) && x
->pos
== IS_RIGHT
) {
200 y
= rcu_dereference(y
->p
);
205 struct rcu_rbtree_node
*rcu_rbtree_prev(struct rcu_rbtree
*rbtree
,
206 struct rcu_rbtree_node
*x
)
208 struct rcu_rbtree_node
*xl
, *y
;
210 x
= rcu_dereference(x
);
212 if (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->left
)))
213 return rcu_rbtree_min(rbtree
, xl
);
214 y
= rcu_dereference(x
->p
);
215 while (!rcu_rbtree_is_nil(y
) && x
->pos
== IS_LEFT
) {
217 y
= rcu_dereference(y
->p
);
223 * We have to ensure these assumptions are correct for prev/next
226 * with x being a right child, the assumption that:
228 * or if x is a left child, the assumption that:
231 * This explains why we have to allocate a vc copy of the node for left_rotate,
232 * right_rotate and transplant operations.
234 * We always ensure that the right/left child and correct parent is set in the
235 * node copies *before* we reparent the children and make the upper-level point
239 /* RCU: copy x and y, atomically point to new versions. GC old. */
240 /* Should be eventually followed by a cmm_smp_wmc() */
242 #ifdef RBTREE_RCU_SUPPORT_ROTATE
244 void left_rotate(struct rcu_rbtree
*rbtree
,
245 struct rcu_rbtree_node
*x
)
247 struct rcu_rbtree_node
*y
, *y_left
, *x_p
;
253 /* Now operate on new copy, decay old versions */
254 //x = dup_decay_node(rbtree, x);
255 //y = dup_decay_node(rbtree, y);
256 //y_left = dup_decay_node(rbtree, y_left);
261 /* Internal node modifications */
268 if (!rcu_rbtree_is_nil(y_left
)) {
270 y_left
->pos
= IS_RIGHT
;
273 cmm_smp_wmb(); /* write into node before publish */
275 /* External references update (visible by readers) */
276 if (rcu_rbtree_is_nil(x_p
))
277 _CMM_STORE_SHARED(rbtree
->root
, y
);
278 else if (x_pos
== IS_LEFT
)
279 _CMM_STORE_SHARED(x_p
->left
, y
);
281 _CMM_STORE_SHARED(x_p
->right
, y
);
283 /* Point children to new copy (parent only used by updates) */
284 if (!rcu_rbtree_is_nil(x
->left
))
286 if (!rcu_rbtree_is_nil(y
->right
))
290 assert(y
== rbtree
->root
|| y
->p
->left
== y
|| y
->p
->right
== y
);
291 assert(x
== rbtree
->root
|| x
->p
->left
== x
|| x
->p
->right
== x
);
292 assert(rcu_rbtree_is_nil(x
->right
) || x
->right
->p
== x
);
293 assert(rcu_rbtree_is_nil(x
->left
) || x
->left
->p
== x
);
294 assert(rcu_rbtree_is_nil(y
->right
) || y
->right
->p
== y
);
295 assert(rcu_rbtree_is_nil(y
->left
) || y
->left
->p
== y
);
296 assert(!is_decay(rbtree
->root
));
297 assert(!is_decay(x
));
298 assert(!is_decay(y
));
299 assert(!is_decay(x
->right
));
300 assert(!is_decay(x
->left
));
301 assert(!is_decay(y
->right
));
302 assert(!is_decay(y
->left
));
306 void right_rotate(struct rcu_rbtree
*rbtree
,
307 struct rcu_rbtree_node
*x
)
309 struct rcu_rbtree_node
*y
, *y_right
, *x_p
;
315 /* Now operate on new copy, decay old versions */
316 //x = dup_decay_node(rbtree, x);
317 //y = dup_decay_node(rbtree, y);
318 //y_right = dup_decay_node(rbtree, y_right);
323 /* Internal node modifications */
330 if (!rcu_rbtree_is_nil(y_right
)) {
332 y_right
->pos
= IS_LEFT
;
335 cmm_smp_wmb(); /* write into node before publish */
337 /* External references update (visible by readers) */
338 if (rcu_rbtree_is_nil(x_p
))
339 _CMM_STORE_SHARED(rbtree
->root
, y
);
340 else if (x_pos
== IS_RIGHT
)
341 _CMM_STORE_SHARED(x_p
->right
, y
);
343 _CMM_STORE_SHARED(x_p
->left
, y
);
345 /* Point children to new copy (parent only used by updates) */
346 if (!rcu_rbtree_is_nil(x
->right
))
348 if (!rcu_rbtree_is_nil(y
->left
))
352 assert(y
== rbtree
->root
|| y
->p
->right
== y
|| y
->p
->left
== y
);
353 assert(x
== rbtree
->root
|| x
->p
->right
== x
|| x
->p
->left
== x
);
354 assert(rcu_rbtree_is_nil(x
->left
) || x
->left
->p
== x
);
355 assert(rcu_rbtree_is_nil(x
->right
) || x
->right
->p
== x
);
356 assert(rcu_rbtree_is_nil(y
->left
) || y
->left
->p
== y
);
357 assert(rcu_rbtree_is_nil(y
->right
) || y
->right
->p
== y
);
358 assert(!is_decay(rbtree
->root
));
359 assert(!is_decay(x
));
360 assert(!is_decay(y
));
361 assert(!is_decay(x
->left
));
362 assert(!is_decay(x
->right
));
363 assert(!is_decay(y
->left
));
364 assert(!is_decay(y
->right
));
369 /* non-rcu versions */
371 void left_rotate(struct rcu_rbtree
*rbtree
,
372 struct rcu_rbtree_node
*x
)
374 struct rcu_rbtree_node
*y
;
378 if (!rcu_rbtree_is_nil(y
->left
)) {
380 y
->left
->pos
= IS_RIGHT
;
383 if (rcu_rbtree_is_nil(x
->p
))
385 else if (x
== x
->p
->left
) {
398 void right_rotate(struct rcu_rbtree
*rbtree
,
399 struct rcu_rbtree_node
*x
)
401 struct rcu_rbtree_node
*y
;
405 if (!rcu_rbtree_is_nil(y
->right
)) {
407 y
->right
->pos
= IS_LEFT
;
410 if (rcu_rbtree_is_nil(x
->p
))
412 else if (x
== x
->p
->right
) {
426 static void rcu_rbtree_insert_fixup(struct rcu_rbtree
*rbtree
,
427 struct rcu_rbtree_node
*z
)
429 struct rcu_rbtree_node
*y
;
431 dbg_printf("insert fixup %p\n", z
->key
);
432 assert(!is_decay(rbtree
->root
));
434 while (z
->p
->color
== COLOR_RED
) {
435 if (z
->p
== z
->p
->p
->left
) {
437 if (y
->color
== COLOR_RED
) {
438 z
->p
->color
= COLOR_BLACK
;
439 y
->color
= COLOR_BLACK
;
440 z
->p
->p
->color
= COLOR_RED
;
443 if (z
== z
->p
->right
) {
445 left_rotate(rbtree
, z
);
447 assert(!is_decay(rbtree
->root
));
449 z
->p
->color
= COLOR_BLACK
;
450 z
->p
->p
->color
= COLOR_RED
;
451 assert(!is_decay(z
));
452 assert(!is_decay(z
->p
));
453 assert(!is_decay(z
->p
->p
));
454 right_rotate(rbtree
, z
->p
->p
);
455 assert(!is_decay(z
));
456 assert(!is_decay(rbtree
->root
));
460 if (y
->color
== COLOR_RED
) {
461 z
->p
->color
= COLOR_BLACK
;
462 y
->color
= COLOR_BLACK
;
463 z
->p
->p
->color
= COLOR_RED
;
466 if (z
== z
->p
->left
) {
468 right_rotate(rbtree
, z
);
470 assert(!is_decay(rbtree
->root
));
472 z
->p
->color
= COLOR_BLACK
;
473 z
->p
->p
->color
= COLOR_RED
;
474 left_rotate(rbtree
, z
->p
->p
);
475 assert(!is_decay(z
));
476 assert(!is_decay(rbtree
->root
));
480 rbtree
->root
->color
= COLOR_BLACK
;
484 * rcu_rbtree_insert - Insert a node in the RCU rbtree
486 * Returns 0 on success, or < 0 on error.
488 int rcu_rbtree_insert(struct rcu_rbtree
*rbtree
,
489 struct rcu_rbtree_node
*z
)
491 struct rcu_rbtree_node
*x
, *y
;
493 dbg_printf("insert %p\n", z
->key
);
494 assert(!is_decay(rbtree
->root
));
496 y
= make_nil(rbtree
);
498 rbtree
->root
= make_nil(rbtree
);
500 while (!rcu_rbtree_is_nil(x
)) {
502 if (rbtree
->comp(z
->key
, x
->key
) < 0)
510 z
->left
= make_nil(rbtree
);
511 z
->right
= make_nil(rbtree
);
512 z
->color
= COLOR_RED
;
514 z
->decay_next
= NULL
;
516 if (rcu_rbtree_is_nil(y
))
517 z
->pos
= IS_RIGHT
; /* arbitrary for root node */
518 else if (rbtree
->comp(z
->key
, y
->key
) < 0)
524 * Order stores to z (children/parents) before stores that will make it
525 * visible to the rest of the tree.
529 if (rcu_rbtree_is_nil(y
))
530 _CMM_STORE_SHARED(rbtree
->root
, z
);
531 else if (rbtree
->comp(z
->key
, y
->key
) < 0)
532 _CMM_STORE_SHARED(y
->left
, z
);
534 _CMM_STORE_SHARED(y
->right
, z
);
535 rcu_rbtree_insert_fixup(rbtree
, z
);
537 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
546 * Transplant v into u position.
549 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
552 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
553 struct rcu_rbtree_node
*u
,
554 struct rcu_rbtree_node
*v
)
556 dbg_printf("transplant %p\n", v
->key
);
558 //if (!rcu_rbtree_is_nil(v))
559 // v = dup_decay_node(rbtree, v);
561 if (rcu_rbtree_is_nil(u
->p
)) {
563 cmm_smp_wmb(); /* write into node before publish */
564 _CMM_STORE_SHARED(rbtree
->root
, v
);
565 } else if (u
== u
->p
->left
) {
568 cmm_smp_wmb(); /* write into node before publish */
569 _CMM_STORE_SHARED(u
->p
->left
, v
);
573 cmm_smp_wmb(); /* write into node before publish */
574 _CMM_STORE_SHARED(u
->p
->right
, v
);
576 /* Set children parent to new node (only used by updates) */
577 if (!rcu_rbtree_is_nil(v
)) {
578 if (!rcu_rbtree_is_nil(v
->right
))
580 if (!rcu_rbtree_is_nil(v
->left
))
583 assert(!is_decay(rbtree
->root
));
588 /* Non-RCU version */
590 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
591 struct rcu_rbtree_node
*u
,
592 struct rcu_rbtree_node
*v
)
594 dbg_printf("transplant %p\n", v
->key
);
596 if (rcu_rbtree_is_nil(u
->p
))
598 else if (u
== u
->p
->left
) {
610 static void rcu_rbtree_remove_fixup(struct rcu_rbtree
*rbtree
,
611 struct rcu_rbtree_node
*x
)
613 dbg_printf("remove fixup %p\n", x
->key
);
615 while (x
!= rbtree
->root
&& x
->color
== COLOR_BLACK
) {
616 assert(!is_decay(x
->p
));
617 assert(!is_decay(x
->p
->left
));
618 if (x
== x
->p
->left
) {
619 struct rcu_rbtree_node
*w
;
623 if (w
->color
== COLOR_RED
) {
624 w
->color
= COLOR_BLACK
;
625 x
->p
->color
= COLOR_RED
;
626 left_rotate(rbtree
, x
->p
);
628 assert(!is_decay(rbtree
->root
));
631 if (w
->left
->color
== COLOR_BLACK
632 && w
->right
->color
== COLOR_BLACK
) {
633 w
->color
= COLOR_RED
;
635 assert(!is_decay(rbtree
->root
));
636 assert(!is_decay(x
));
638 if (w
->right
->color
== COLOR_BLACK
) {
639 w
->left
->color
= COLOR_BLACK
;
640 w
->color
= COLOR_RED
;
641 right_rotate(rbtree
, w
);
642 assert(!is_decay(rbtree
->root
));
646 w
->color
= x
->p
->color
;
647 x
->p
->color
= COLOR_BLACK
;
648 w
->right
->color
= COLOR_BLACK
;
649 left_rotate(rbtree
, x
->p
);
650 assert(!is_decay(rbtree
->root
));
654 struct rcu_rbtree_node
*w
;
658 if (w
->color
== COLOR_RED
) {
659 w
->color
= COLOR_BLACK
;
660 x
->p
->color
= COLOR_RED
;
661 right_rotate(rbtree
, x
->p
);
662 assert(!is_decay(rbtree
->root
));
666 if (w
->right
->color
== COLOR_BLACK
667 && w
->left
->color
== COLOR_BLACK
) {
668 w
->color
= COLOR_RED
;
670 assert(!is_decay(rbtree
->root
));
671 assert(!is_decay(x
));
673 if (w
->left
->color
== COLOR_BLACK
) {
674 w
->right
->color
= COLOR_BLACK
;
675 w
->color
= COLOR_RED
;
676 left_rotate(rbtree
, w
);
677 assert(!is_decay(rbtree
->root
));
681 w
->color
= x
->p
->color
;
682 x
->p
->color
= COLOR_BLACK
;
683 w
->left
->color
= COLOR_BLACK
;
684 right_rotate(rbtree
, x
->p
);
685 assert(!is_decay(rbtree
->root
));
690 x
->color
= COLOR_BLACK
;
694 * Delete z. All non-copied children left/right positions are unchanged.
697 void rcu_rbtree_remove_nonil(struct rcu_rbtree
*rbtree
,
698 struct rcu_rbtree_node
*z
,
699 struct rcu_rbtree_node
*y
)
701 struct rcu_rbtree_node
*x
;
703 dbg_printf("remove nonil %p\n", z
->key
);
706 assert(!is_decay(z
));
707 assert(!is_decay(y
));
708 assert(!is_decay(y
->right
));
709 assert(!is_decay(y
->p
));
711 assert(!is_decay(x
));
715 rcu_rbtree_transplant(rbtree
, y
, y
->right
);
716 assert(!is_decay(y
));
717 assert(!is_decay(z
));
718 assert(!is_decay(z
->right
));
722 rcu_rbtree_transplant(rbtree
, z
, y
);
724 assert(!is_decay(z
));
725 assert(!is_decay(z
->left
));
731 int rcu_rbtree_remove(struct rcu_rbtree
*rbtree
,
732 struct rcu_rbtree_node
*z
)
734 struct rcu_rbtree_node
*x
, *y
;
735 unsigned int y_original_color
;
737 assert(!is_decay(rbtree
->root
));
738 dbg_printf("remove %p\n", z
->key
);
741 assert(!is_decay(z
));
743 y_original_color
= y
->color
;
745 if (rcu_rbtree_is_nil(z
->left
)) {
746 rcu_rbtree_transplant(rbtree
, z
, z
->right
);
747 assert(!is_decay(z
));
748 x
= get_decay(z
->right
);
750 } else if (rcu_rbtree_is_nil(z
->right
)) {
751 rcu_rbtree_transplant(rbtree
, z
, z
->left
);
752 assert(!is_decay(z
));
753 x
= get_decay(z
->left
);
756 y
= rcu_rbtree_min(rbtree
, z
->right
);
757 assert(!is_decay(y
));
758 y_original_color
= y
->color
;
760 rcu_rbtree_remove_nonil(rbtree
, z
, y
);
764 if (y_original_color
== COLOR_BLACK
)
765 rcu_rbtree_remove_fixup(rbtree
, x
);
768 * Commit all _CMM_STORE_SHARED().
This page took 0.044481 seconds and 5 git commands to generate.