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>
46 #define dbg_printf(args...) printf(args)
48 #define dbg_printf(args...)
52 * Undefine this to enable the non-RCU rotate and transplant functions
55 #define RBTREE_RCU_SUPPORT_ROTATE_LEFT
56 #define RBTREE_RCU_SUPPORT_ROTATE_RIGHT
57 #define RBTREE_RCU_SUPPORT_TRANSPLANT
60 static pthread_mutex_t test_mutex
= PTHREAD_MUTEX_INITIALIZER
;
61 static pthread_mutex_t outer_mutex
= PTHREAD_MUTEX_INITIALIZER
;
64 void lock_outer_mutex(void)
66 pthread_mutex_lock(&outer_mutex
);
70 void unlock_outer_mutex(void)
72 pthread_mutex_unlock(&outer_mutex
);
76 void lock_test_mutex(void)
78 pthread_mutex_lock(&test_mutex
);
82 void unlock_test_mutex(void)
84 pthread_mutex_unlock(&test_mutex
);
89 void set_decay(struct rcu_rbtree_node
*x
, struct rcu_rbtree_node
*xc
)
95 struct rcu_rbtree_node
*get_decay(struct rcu_rbtree_node
*x
)
105 struct rcu_rbtree_node
*is_decay(struct rcu_rbtree_node
*x
)
107 return x
->decay_next
;
111 struct rcu_rbtree_node
*dup_decay_node(struct rcu_rbtree
*rbtree
,
112 struct rcu_rbtree_node
*x
)
114 struct rcu_rbtree_node
*xc
;
116 if (rcu_rbtree_is_nil(x
))
119 xc
= rbtree
->rballoc();
120 memcpy(xc
, x
, sizeof(struct rcu_rbtree_node
));
121 xc
->decay_next
= NULL
;
123 call_rcu(&x
->head
, rbtree
->rbfree
);
129 * Deal with memory allocation errors.
130 * Can be ensured by reserving a pool of memory entries before doing the
131 * insertion, which will have to be function of number of
132 * transplantations/rotations required for the operation.
136 void show_tree(struct rcu_rbtree
*rbtree
)
138 struct rcu_rbtree_node
*node
;
140 node
= rcu_rbtree_min(rbtree
, rbtree
->root
);
141 while (!rcu_rbtree_is_nil(node
)) {
142 assert(!is_decay(node
));
143 printf("{ 0x%lX p:%lX r:%lX l:%lX %s %s %s} ",
144 (unsigned long)node
->key
,
145 (unsigned long) node
->p
->key
,
146 (unsigned long) node
->right
->key
,
147 (unsigned long) node
->left
->key
,
148 node
->color
? "red" : "black",
149 node
->pos
? "right" : "left",
150 node
->nil
? "nil" : "");
151 node
= rcu_rbtree_next(rbtree
, node
);
157 struct rcu_rbtree_node
*make_nil(struct rcu_rbtree
*rbtree
)
159 return &rbtree
->nil_node
;
163 * Iterative rbtree search.
165 struct rcu_rbtree_node
* rcu_rbtree_search(struct rcu_rbtree
*rbtree
,
166 struct rcu_rbtree_node
*x
,
169 x
= rcu_dereference(x
);
171 while (!rcu_rbtree_is_nil(x
) && k
!= x
->key
) {
173 if (rbtree
->comp(k
, x
->key
) < 0)
174 x
= rcu_dereference(x
->left
);
176 x
= rcu_dereference(x
->right
);
182 struct rcu_rbtree_node
*rcu_rbtree_min_dup_decay(struct rcu_rbtree
*rbtree
,
183 struct rcu_rbtree_node
*x
,
184 struct rcu_rbtree_node
**zr
)
186 struct rcu_rbtree_node
*xl
;
188 x
= rcu_dereference(x
);
190 if (rcu_rbtree_is_nil(x
)) {
194 *zr
= x
= dup_decay_node(rbtree
, x
);
196 while (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->left
))) {
197 x
= dup_decay_node(rbtree
, xl
);
198 x
->p
= get_decay(x
->p
);
199 x
->p
->left
= get_decay(x
->p
->left
);
205 struct rcu_rbtree_node
*rcu_rbtree_min_update_decay(struct rcu_rbtree
*rbtree
,
206 struct rcu_rbtree_node
*x
)
208 struct rcu_rbtree_node
*xl
;
210 x
= rcu_dereference(x
);
212 if (rcu_rbtree_is_nil(x
))
215 x
->right
->p
= get_decay(x
->right
->p
);
216 x
->left
->p
= get_decay(x
->left
->p
);
219 while (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->left
))) {
221 xl
->right
->p
= get_decay(xl
->right
->p
);
222 xl
->left
->p
= get_decay(xl
->left
->p
);
227 struct rcu_rbtree_node
*rcu_rbtree_min(struct rcu_rbtree
*rbtree
,
228 struct rcu_rbtree_node
*x
)
230 struct rcu_rbtree_node
*xl
;
232 x
= rcu_dereference(x
);
234 if (rcu_rbtree_is_nil(x
))
237 while (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->left
)))
242 struct rcu_rbtree_node
*rcu_rbtree_max(struct rcu_rbtree
*rbtree
,
243 struct rcu_rbtree_node
*x
)
245 struct rcu_rbtree_node
*xr
;
247 x
= rcu_dereference(x
);
249 if (rcu_rbtree_is_nil(x
))
252 while (!rcu_rbtree_is_nil(xr
= rcu_dereference(x
->right
)))
259 * Updates should wait for a grace period between update of the
260 * redirect pointer and update of the parent child pointer. This is to make sure
261 * that no reference to the old entry exist.
265 * next and prev need to have mutex held to ensure that parent pointer is
268 struct rcu_rbtree_node
*rcu_rbtree_next(struct rcu_rbtree
*rbtree
,
269 struct rcu_rbtree_node
*x
)
271 struct rcu_rbtree_node
*xr
, *y
;
273 x
= rcu_dereference(x
);
275 if (!rcu_rbtree_is_nil(xr
= rcu_dereference(x
->right
)))
276 return rcu_rbtree_min(rbtree
, xr
);
277 y
= rcu_dereference(x
->p
);
278 while (!rcu_rbtree_is_nil(y
) && x
->pos
== IS_RIGHT
) {
280 y
= rcu_dereference(y
->p
);
285 struct rcu_rbtree_node
*rcu_rbtree_prev(struct rcu_rbtree
*rbtree
,
286 struct rcu_rbtree_node
*x
)
288 struct rcu_rbtree_node
*xl
, *y
;
290 x
= rcu_dereference(x
);
292 if (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->left
)))
293 return rcu_rbtree_min(rbtree
, xl
);
294 y
= rcu_dereference(x
->p
);
295 while (!rcu_rbtree_is_nil(y
) && x
->pos
== IS_LEFT
) {
297 y
= rcu_dereference(y
->p
);
303 * We have to ensure these assumptions are correct for prev/next
306 * with x being a right child, the assumption that:
308 * or if x is a left child, the assumption that:
311 * This explains why we have to allocate a vc copy of the node for left_rotate,
312 * right_rotate and transplant operations.
314 * We always ensure that the right/left child and correct parent is set in the
315 * node copies *before* we reparent the children and make the upper-level point
319 /* RCU: copy x and y, atomically point to new versions. GC old. */
320 /* Should be eventually followed by a cmm_smp_wmc() */
322 #ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
325 void left_rotate(struct rcu_rbtree
*rbtree
,
326 struct rcu_rbtree_node
*x
)
328 struct rcu_rbtree_node
*y
, *y_left
, *x_p
;
334 /* Now operate on new copy, decay old versions */
335 x
= dup_decay_node(rbtree
, x
);
336 y
= dup_decay_node(rbtree
, y
);
337 y_left
= dup_decay_node(rbtree
, y_left
);
342 /* Internal node modifications */
349 if (!rcu_rbtree_is_nil(y_left
)) {
351 y_left
->pos
= IS_RIGHT
;
354 cmm_smp_wmb(); /* write into node before publish */
356 /* External references update (visible by readers) */
357 if (rcu_rbtree_is_nil(x_p
))
358 _CMM_STORE_SHARED(rbtree
->root
, y
);
359 else if (x_pos
== IS_LEFT
)
360 _CMM_STORE_SHARED(x_p
->left
, y
);
362 _CMM_STORE_SHARED(x_p
->right
, y
);
364 /* Point children to new copy (parent only used by updates/next/prev) */
365 x
->left
->p
= get_decay(x
->left
->p
);
366 y
->right
->p
= get_decay(y
->right
->p
);
367 if (!rcu_rbtree_is_nil(y_left
)) {
368 y_left
->right
->p
= get_decay(y_left
->right
->p
);
369 y_left
->left
->p
= get_decay(y_left
->left
->p
);
373 assert(y
== rbtree
->root
|| y
->p
->left
== y
|| y
->p
->right
== y
);
374 assert(x
== rbtree
->root
|| x
->p
->left
== x
|| x
->p
->right
== x
);
375 assert(rcu_rbtree_is_nil(x
->right
) || x
->right
->p
== x
);
376 assert(rcu_rbtree_is_nil(x
->left
) || x
->left
->p
== x
);
377 assert(rcu_rbtree_is_nil(y
->right
) || y
->right
->p
== y
);
378 assert(rcu_rbtree_is_nil(y
->left
) || y
->left
->p
== y
);
379 assert(!is_decay(rbtree
->root
));
380 assert(!is_decay(x
));
381 assert(!is_decay(y
));
382 assert(!is_decay(x
->right
));
383 assert(!is_decay(x
->left
));
384 assert(!is_decay(y
->right
));
385 assert(!is_decay(y
->left
));
390 /* non-rcu version */
392 void left_rotate(struct rcu_rbtree
*rbtree
,
393 struct rcu_rbtree_node
*x
)
395 struct rcu_rbtree_node
*y
;
400 if (!rcu_rbtree_is_nil(y
->left
)) {
402 y
->left
->pos
= IS_RIGHT
;
405 if (rcu_rbtree_is_nil(x
->p
))
407 else if (x
== x
->p
->left
) {
422 #ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
424 void right_rotate(struct rcu_rbtree
*rbtree
,
425 struct rcu_rbtree_node
*x
)
427 struct rcu_rbtree_node
*y
, *y_right
, *x_p
;
433 /* Now operate on new copy, decay old versions */
434 x
= dup_decay_node(rbtree
, x
);
435 y
= dup_decay_node(rbtree
, y
);
436 y_right
= dup_decay_node(rbtree
, y_right
);
441 /* Internal node modifications */
448 if (!rcu_rbtree_is_nil(y_right
)) {
450 y_right
->pos
= IS_LEFT
;
453 cmm_smp_wmb(); /* write into node before publish */
455 /* External references update (visible by readers) */
456 if (rcu_rbtree_is_nil(x_p
))
457 _CMM_STORE_SHARED(rbtree
->root
, y
);
458 else if (x_pos
== IS_RIGHT
)
459 _CMM_STORE_SHARED(x_p
->right
, y
);
461 _CMM_STORE_SHARED(x_p
->left
, y
);
463 /* Point children to new copy (parent only used by updates/next/prev) */
464 x
->right
->p
= get_decay(x
->right
->p
);
465 y
->left
->p
= get_decay(y
->left
->p
);
466 if (!rcu_rbtree_is_nil(y_right
)) {
467 y_right
->left
->p
= get_decay(y_right
->left
->p
);
468 y_right
->right
->p
= get_decay(y_right
->right
->p
);
472 assert(y
== rbtree
->root
|| y
->p
->right
== y
|| y
->p
->left
== y
);
473 assert(x
== rbtree
->root
|| x
->p
->right
== x
|| x
->p
->left
== x
);
474 assert(rcu_rbtree_is_nil(x
->left
) || x
->left
->p
== x
);
475 assert(rcu_rbtree_is_nil(x
->right
) || x
->right
->p
== x
);
476 assert(rcu_rbtree_is_nil(y
->left
) || y
->left
->p
== y
);
477 assert(rcu_rbtree_is_nil(y
->right
) || y
->right
->p
== y
);
478 assert(!is_decay(rbtree
->root
));
479 assert(!is_decay(x
));
480 assert(!is_decay(y
));
481 assert(!is_decay(x
->left
));
482 assert(!is_decay(x
->right
));
483 assert(!is_decay(y
->left
));
484 assert(!is_decay(y
->right
));
489 /* non-rcu version */
491 void right_rotate(struct rcu_rbtree
*rbtree
,
492 struct rcu_rbtree_node
*x
)
494 struct rcu_rbtree_node
*y
;
499 if (!rcu_rbtree_is_nil(y
->right
)) {
501 y
->right
->pos
= IS_LEFT
;
504 if (rcu_rbtree_is_nil(x
->p
))
506 else if (x
== x
->p
->right
) {
521 static void rcu_rbtree_insert_fixup(struct rcu_rbtree
*rbtree
,
522 struct rcu_rbtree_node
*z
)
524 struct rcu_rbtree_node
*y
;
526 dbg_printf("insert fixup %p\n", z
->key
);
527 assert(!is_decay(rbtree
->root
));
529 while (z
->p
->color
== COLOR_RED
) {
530 if (z
->p
== z
->p
->p
->left
) {
532 if (y
->color
== COLOR_RED
) {
533 z
->p
->color
= COLOR_BLACK
;
534 y
->color
= COLOR_BLACK
;
535 z
->p
->p
->color
= COLOR_RED
;
538 if (z
== z
->p
->right
) {
540 left_rotate(rbtree
, z
);
542 assert(!is_decay(rbtree
->root
));
544 z
->p
->color
= COLOR_BLACK
;
545 z
->p
->p
->color
= COLOR_RED
;
546 assert(!is_decay(z
));
547 assert(!is_decay(z
->p
));
548 assert(!is_decay(z
->p
->p
));
549 right_rotate(rbtree
, z
->p
->p
);
550 assert(!is_decay(z
));
551 assert(!is_decay(rbtree
->root
));
555 if (y
->color
== COLOR_RED
) {
556 z
->p
->color
= COLOR_BLACK
;
557 y
->color
= COLOR_BLACK
;
558 z
->p
->p
->color
= COLOR_RED
;
561 if (z
== z
->p
->left
) {
563 right_rotate(rbtree
, z
);
565 assert(!is_decay(rbtree
->root
));
567 z
->p
->color
= COLOR_BLACK
;
568 z
->p
->p
->color
= COLOR_RED
;
569 left_rotate(rbtree
, z
->p
->p
);
570 assert(!is_decay(z
));
571 assert(!is_decay(rbtree
->root
));
575 rbtree
->root
->color
= COLOR_BLACK
;
579 * rcu_rbtree_insert - Insert a node in the RCU rbtree
581 * Returns 0 on success, or < 0 on error.
583 int rcu_rbtree_insert(struct rcu_rbtree
*rbtree
,
584 struct rcu_rbtree_node
*z
)
586 struct rcu_rbtree_node
*x
, *y
;
588 dbg_printf("insert %p\n", z
->key
);
589 assert(!is_decay(rbtree
->root
));
591 y
= make_nil(rbtree
);
593 rbtree
->root
= make_nil(rbtree
);
595 while (!rcu_rbtree_is_nil(x
)) {
597 if (rbtree
->comp(z
->key
, x
->key
) < 0)
605 z
->left
= make_nil(rbtree
);
606 z
->right
= make_nil(rbtree
);
607 z
->color
= COLOR_RED
;
609 z
->decay_next
= NULL
;
611 if (rcu_rbtree_is_nil(y
))
612 z
->pos
= IS_RIGHT
; /* arbitrary for root node */
613 else if (rbtree
->comp(z
->key
, y
->key
) < 0)
619 * Order stores to z (children/parents) before stores that will make it
620 * visible to the rest of the tree.
624 if (rcu_rbtree_is_nil(y
))
625 _CMM_STORE_SHARED(rbtree
->root
, z
);
626 else if (rbtree
->comp(z
->key
, y
->key
) < 0)
627 _CMM_STORE_SHARED(y
->left
, z
);
629 _CMM_STORE_SHARED(y
->right
, z
);
630 rcu_rbtree_insert_fixup(rbtree
, z
);
632 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
641 * Transplant v into u position.
644 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
647 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
648 struct rcu_rbtree_node
*u
,
649 struct rcu_rbtree_node
*v
)
651 dbg_printf("transplant %p\n", v
->key
);
653 if (!rcu_rbtree_is_nil(v
))
654 v
= dup_decay_node(rbtree
, v
);
656 if (rcu_rbtree_is_nil(u
->p
)) {
658 cmm_smp_wmb(); /* write into node before publish */
659 _CMM_STORE_SHARED(rbtree
->root
, v
);
663 cmm_smp_wmb(); /* write into node before publish */
664 if (u
->pos
== IS_LEFT
)
665 _CMM_STORE_SHARED(u
->p
->left
, v
);
667 _CMM_STORE_SHARED(u
->p
->right
, v
);
670 /* Point children to new copy (parent only used by updates/next/prev) */
671 if (!rcu_rbtree_is_nil(v
)) {
672 v
->right
->p
= get_decay(v
->right
->p
);
673 v
->left
->p
= get_decay(v
->left
->p
);
675 assert(!is_decay(rbtree
->root
));
680 /* Non-RCU version */
682 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
683 struct rcu_rbtree_node
*u
,
684 struct rcu_rbtree_node
*v
)
686 dbg_printf("transplant %p\n", v
->key
);
689 if (rcu_rbtree_is_nil(u
->p
))
691 else if (u
== u
->p
->left
) {
704 static void rcu_rbtree_remove_fixup(struct rcu_rbtree
*rbtree
,
705 struct rcu_rbtree_node
*x
)
707 dbg_printf("remove fixup %p\n", x
->key
);
709 while (x
!= rbtree
->root
&& x
->color
== COLOR_BLACK
) {
710 assert(!is_decay(x
->p
));
711 assert(!is_decay(x
->p
->left
));
712 if (x
== x
->p
->left
) {
713 struct rcu_rbtree_node
*w
;
717 if (w
->color
== COLOR_RED
) {
718 w
->color
= COLOR_BLACK
;
719 x
->p
->color
= COLOR_RED
;
720 left_rotate(rbtree
, x
->p
);
722 assert(!is_decay(rbtree
->root
));
725 if (w
->left
->color
== COLOR_BLACK
726 && w
->right
->color
== COLOR_BLACK
) {
727 w
->color
= COLOR_RED
;
729 assert(!is_decay(rbtree
->root
));
730 assert(!is_decay(x
));
732 if (w
->right
->color
== COLOR_BLACK
) {
733 w
->left
->color
= COLOR_BLACK
;
734 w
->color
= COLOR_RED
;
735 right_rotate(rbtree
, w
);
736 assert(!is_decay(rbtree
->root
));
740 w
->color
= x
->p
->color
;
741 x
->p
->color
= COLOR_BLACK
;
742 w
->right
->color
= COLOR_BLACK
;
743 left_rotate(rbtree
, x
->p
);
744 assert(!is_decay(rbtree
->root
));
748 struct rcu_rbtree_node
*w
;
752 if (w
->color
== COLOR_RED
) {
753 w
->color
= COLOR_BLACK
;
754 x
->p
->color
= COLOR_RED
;
755 right_rotate(rbtree
, x
->p
);
756 assert(!is_decay(rbtree
->root
));
760 if (w
->right
->color
== COLOR_BLACK
761 && w
->left
->color
== COLOR_BLACK
) {
762 w
->color
= COLOR_RED
;
764 assert(!is_decay(rbtree
->root
));
765 assert(!is_decay(x
));
767 if (w
->left
->color
== COLOR_BLACK
) {
768 w
->right
->color
= COLOR_BLACK
;
769 w
->color
= COLOR_RED
;
770 left_rotate(rbtree
, w
);
771 assert(!is_decay(rbtree
->root
));
775 w
->color
= x
->p
->color
;
776 x
->p
->color
= COLOR_BLACK
;
777 w
->left
->color
= COLOR_BLACK
;
778 right_rotate(rbtree
, x
->p
);
779 assert(!is_decay(rbtree
->root
));
784 x
->color
= COLOR_BLACK
;
788 * Delete z. All non-copied children left/right positions are unchanged.
791 void rcu_rbtree_remove_nonil(struct rcu_rbtree
*rbtree
,
792 struct rcu_rbtree_node
*z
,
793 struct rcu_rbtree_node
*y
)
795 struct rcu_rbtree_node
*x
;
797 dbg_printf("remove nonil %p\n", z
->key
);
800 assert(!is_decay(z
));
801 assert(!is_decay(y
));
802 assert(!is_decay(y
->right
));
803 assert(!is_decay(y
->p
));
805 assert(!is_decay(x
));
807 y
= dup_decay_node(rbtree
, y
);
810 rcu_rbtree_transplant(rbtree
, z
, y
);
812 struct rcu_rbtree_node
*oy_right
, *z_right
;
815 * Need to make sure y is always visible by readers.
817 y
= rcu_rbtree_min_dup_decay(rbtree
, z
->right
, &z_right
);
818 assert(!is_decay(y
));
819 assert(!is_decay(z
));
823 assert(!is_decay(z
->left
));
825 assert(!is_decay(oy_right
));
826 rcu_rbtree_transplant(rbtree
, y
, oy_right
);
827 rcu_rbtree_transplant(rbtree
, z
, y
);
828 /* Update children */
829 (void) rcu_rbtree_min_update_decay(rbtree
, y
->right
);
832 assert(!is_decay(z
));
833 assert(!is_decay(z
->left
));
836 y
->right
->p
= get_decay(y
->right
->p
);
837 assert(!is_decay(y
->left
));
838 assert(!is_decay(y
->right
));
841 int rcu_rbtree_remove(struct rcu_rbtree
*rbtree
,
842 struct rcu_rbtree_node
*z
)
844 struct rcu_rbtree_node
*x
, *y
;
845 unsigned int y_original_color
;
847 assert(!is_decay(rbtree
->root
));
848 dbg_printf("remove %p\n", z
->key
);
851 assert(!is_decay(z
));
853 y_original_color
= y
->color
;
855 if (rcu_rbtree_is_nil(z
->left
)) {
856 rcu_rbtree_transplant(rbtree
, z
, z
->right
);
857 assert(!is_decay(z
));
858 x
= get_decay(z
->right
);
860 } else if (rcu_rbtree_is_nil(z
->right
)) {
861 rcu_rbtree_transplant(rbtree
, z
, z
->left
);
862 assert(!is_decay(z
));
863 x
= get_decay(z
->left
);
866 y
= rcu_rbtree_min(rbtree
, z
->right
);
867 assert(!is_decay(y
));
868 y_original_color
= y
->color
;
870 rcu_rbtree_remove_nonil(rbtree
, z
, y
);
874 if (y_original_color
== COLOR_BLACK
)
875 rcu_rbtree_remove_fixup(rbtree
, x
);
878 * Commit all _CMM_STORE_SHARED().