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.
37 #include <urcu-rbtree.h>
38 #include <urcu-pointer.h>
42 * Deal with memory allocation errors.
43 * Can be ensured by reserving a pool of memory entries before doing the
44 * insertion, which will have to be function of number of
45 * transplantations/rotations required for the operation.
48 /* Sentinel (bottom nodes).
49 * Don't care about p, left, right, pos and key values */
50 struct rcu_rbtree_node rcu_rbtree_nil
= {
55 * Iterative rbtree search.
57 struct rcu_rbtree_node
* rcu_rbtree_search(struct rcu_rbtree_node
*x
,
58 void *k
, rcu_rbtree_comp comp
)
60 x
= rcu_dereference(x
);
62 while (x
!= &rcu_rbtree_nil
&& k
!= x
->key
) {
64 x
= rcu_dereference(x
->left
);
66 x
= rcu_dereference(x
->right
);
71 struct rcu_rbtree_node
*rcu_rbtree_min(struct rcu_rbtree_node
*x
,
74 struct rcu_rbtree_node
*xl
;
76 x
= rcu_dereference(x
);
78 while ((xl
= rcu_dereference(x
->left
)) != &rcu_rbtree_nil
)
83 struct rcu_rbtree_node
*rcu_rbtree_max(struct rcu_rbtree_node
*x
,
86 struct rcu_rbtree_node
*xr
;
88 x
= rcu_dereference(x
);
90 while ((xr
= rcu_dereference(x
->right
)) != &rcu_rbtree_nil
)
97 * Updates should wait for a grace period between update of the
98 * redirect pointer and update of the parent child pointer. This is to make sure
99 * that no reference to the old entry exist.
103 * next and prev need to have mutex held to ensure that parent pointer is
106 struct rcu_rbtree_node
*rcu_rbtree_next(struct rcu_rbtree_node
*x
,
107 rcu_rbtree_comp comp
)
109 struct rcu_rbtree_node
*xr
, *y
, *yr
;
111 x
= rcu_dereference(x
);
113 if ((xr
= rcu_dereference(x
->right
)) != &rcu_rbtree_nil
)
114 return rcu_rbtree_min(xr
, comp
);
115 y
= rcu_dereference(x
->p
);
116 while (y
!= &rcu_rbtree_nil
&& x
->pos
== IS_RIGHT
) {
118 y
= rcu_dereference(y
->p
);
123 struct rcu_rbtree_node
*rcu_rbtree_prev(struct rcu_rbtree_node
*x
,
124 rcu_rbtree_comp comp
)
126 struct rcu_rbtree_node
*xl
, *y
, *yl
;
128 x
= rcu_dereference(x
);
130 if ((xl
= rcu_dereference(x
->left
)) != &rcu_rbtree_nil
)
131 return rcu_rbtree_min(xl
, comp
);
132 y
= rcu_dereference(x
->p
);
133 while (y
!= &rcu_rbtree_nil
&& x
->pos
== IS_LEFT
) {
135 y
= rcu_dereference(y
->p
);
141 * We have to ensure these assumptions are correct for prev/next
144 * with x being a right child, the assumption that:
146 * or if x is a left child, the assumption that:
149 * This explains why we have to allocate a vc copy of the node for left_rotate,
150 * right_rotate and transplant operations.
152 * We always ensure that the right/left child and correct parent is set in the
153 * node copies *before* we reparent the children and make the upper-level point
157 /* RCU: copy x and y, atomically point to new versions. GC old. */
158 /* Should be eventually followed by a smp_wmc() */
159 /* Returns the new x. Previous x->right references are changed to yc.
160 * Previous y->left->right is changed to bc. */
161 static struct rcu_rbtree_node
*left_rotate(struct rcu_rbtree_node
**root
,
162 struct rcu_rbtree_node
*x
,
163 rcu_rbtree_alloc rballoc
,
164 rcu_rbtree_free rbfree
)
166 struct rcu_rbtree_node
*xc
, *y
, *yc
, *b
, *bc
;
170 if (x
!= &rcu_rbtree_nil
) {
176 if (y
!= &rcu_rbtree_nil
) {
185 if (b
!= &rcu_rbtree_nil
) {
186 /* Beta position changes from left to right. */
189 assert(b
->pos
== IS_LEFT
);
193 /* Modify children and parents in the node copies */
194 if (x
!= &rcu_rbtree_nil
) {
198 xc
= &rcu_rbtree_nil
;
200 if (y
!= &rcu_rbtree_nil
) {
204 yc
= &rcu_rbtree_nil
;
207 * Order stores to node copies (children/parents) before stores that
208 * will make the copies visible to the rest of the tree.
212 /* Make parents point to the copies */
213 if (x
->p
== &rcu_rbtree_nil
)
214 _STORE_SHARED(*root
, yc
);
215 else if (x
->pos
== IS_LEFT
)
216 _STORE_SHARED(x
->p
->left
, yc
);
218 _STORE_SHARED(x
->p
->right
, yc
);
220 /* Assign children parents to copies */
221 if (x
!= &rcu_rbtree_nil
) {
222 _STORE_SHARED(xc
->left
->p
, xc
); /* alpha stays left */
223 defer_rcu(rbfree
, x
);
225 if (y
!= &rcu_rbtree_nil
) {
226 _STORE_SHARED(yc
->right
->p
, yc
);/* gamma stays right */
227 defer_rcu(rbfree
, y
);
228 /* yc->left is xc, its parent is already set in node copy */
230 if (b
!= &rcu_rbtree_nil
) {
231 _STORE_SHARED(bc
->right
->p
, bc
);
232 _STORE_SHARED(bc
->left
->p
, bc
);
233 defer_rcu(rbfree
, b
);
239 static void left_rotate(struct rcu_rbtree_node
**root
,
240 struct rcu_rbtree_node
*x
,
241 rcu_rbtree_alloc rballoc
)
243 struct rcu_rbtree_node
*y
;
247 if (y
->left
!= &rcu_rbtree_nil
)
250 if (x
->p
== &rcu_rbtree_nil
)
252 else if (x
== x
->p
->left
)
261 /* RCU: copy x and y, atomically point to new versions. GC old. */
262 /* Should be eventually followed by a smp_wmc() */
263 /* Returns the new y. Previous y->left references are changed to xc.
264 * Previous y->left->right is changed to bc */
265 static struct rcu_rbtree_node
*right_rotate(struct rcu_rbtree_node
**root
,
266 struct rcu_rbtree_node
*y
,
267 rcu_rbtree_alloc rballoc
,
268 rcu_rbtree_free rbfree
)
270 struct rcu_rbtree_node
*x
, *xc
, *yc
, *b
, *bc
;;
274 if (x
!= &rcu_rbtree_nil
) {
283 if (y
!= &rcu_rbtree_nil
) {
289 if (b
!= &rcu_rbtree_nil
) {
290 /* Beta position changes from right to left. */
293 assert(b
->pos
== IS_RIGHT
);
297 /* Modify children and parents in the node copies */
298 if (x
!= &rcu_rbtree_nil
) {
302 xc
= &rcu_rbtree_nil
;
304 if (y
!= &rcu_rbtree_nil
) {
308 yc
= &rcu_rbtree_nil
;
311 * Order stores to node copies (children/parents) before stores that
312 * will make the copies visible to the rest of the tree.
316 /* Make parents point to the copies */
317 if (y
->p
== &rcu_rbtree_nil
)
318 _STORE_SHARED(*root
, xc
);
319 else if (y
->pos
== IS_RIGHT
)
320 _STORE_SHARED(y
->p
->right
, xc
);
322 _STORE_SHARED(y
->p
->left
, xc
);
324 /* Assign children parents to copies */
325 if (x
!= &rcu_rbtree_nil
) {
326 _STORE_SHARED(xc
->left
->p
, xc
); /* alpha stays left */
327 /* xc->right is yc, its parent is already set in node copy */
328 defer_rcu(rbfree
, x
);
330 if (y
!= &rcu_rbtree_nil
) {
331 _STORE_SHARED(yc
->right
->p
, yc
);/* gamma stays right */
332 defer_rcu(rbfree
, y
);
334 if (b
!= &rcu_rbtree_nil
) {
335 _STORE_SHARED(bc
->right
->p
, bc
);
336 _STORE_SHARED(bc
->left
->p
, bc
);
337 defer_rcu(rbfree
, b
);
343 static void right_rotate(struct rcu_rbtree_node
**root
,
344 struct rcu_rbtree_node
*x
,
345 rcu_rbtree_alloc rballoc
)
347 struct rcu_rbtree_node
*y
;
351 if (y
->right
!= &rcu_rbtree_nil
)
354 if (x
->p
== &rcu_rbtree_nil
)
356 else if (x
== x
->p
->right
)
365 static void rcu_rbtree_insert_fixup(struct rcu_rbtree_node
**root
,
366 struct rcu_rbtree_node
*z
,
367 rcu_rbtree_alloc rballoc
,
368 rcu_rbtree_free rbfree
)
370 struct rcu_rbtree_node
*y
;
372 while (z
->p
->color
== COLOR_RED
) {
373 if (z
->p
== z
->p
->p
->left
) {
375 if (y
->color
== COLOR_RED
) {
376 z
->p
->color
= COLOR_BLACK
;
377 y
->color
= COLOR_BLACK
;
378 z
->p
->p
->color
= COLOR_RED
;
381 if (z
== z
->p
->right
) {
383 z
= left_rotate(root
, z
,
386 z
->p
->color
= COLOR_BLACK
;
387 z
->p
->p
->color
= COLOR_RED
;
388 right_rotate(root
, z
->p
->p
, rballoc
, rbfree
);
392 if (y
->color
== COLOR_RED
) {
393 z
->p
->color
= COLOR_BLACK
;
394 y
->color
= COLOR_BLACK
;
395 z
->p
->p
->color
= COLOR_RED
;
398 if (z
== z
->p
->left
) {
400 z
= right_rotate(root
, z
,
403 z
->p
->color
= COLOR_BLACK
;
404 z
->p
->p
->color
= COLOR_RED
;
405 left_rotate(root
, z
->p
->p
, rballoc
, rbfree
);
409 (*root
)->color
= COLOR_BLACK
;
413 * rcu_rbtree_insert - Insert a node in the RCU rbtree
415 * Returns 0 on success, or < 0 on error.
417 int rcu_rbtree_insert(struct rcu_rbtree_node
**root
,
418 struct rcu_rbtree_node
*z
,
419 rcu_rbtree_comp comp
,
420 rcu_rbtree_alloc rballoc
,
421 rcu_rbtree_free rbfree
)
423 struct rcu_rbtree_node
*x
, *y
;
428 while (x
!= &rcu_rbtree_nil
) {
430 if (comp(z
->key
, x
->key
) < 0)
437 z
->left
= &rcu_rbtree_nil
;
438 z
->right
= &rcu_rbtree_nil
;
439 z
->color
= COLOR_RED
;
441 if (y
== &rcu_rbtree_nil
)
442 z
->pos
= IS_RIGHT
; /* arbitrary for root node */
443 else if (comp(z
->key
, y
->key
) < 0)
449 * Order stores to z (children/parents) before stores that will make it
450 * visible to the rest of the tree.
454 if (y
== &rcu_rbtree_nil
)
455 _STORE_SHARED(*root
, z
);
456 else if (comp(z
->key
, y
->key
) < 0)
457 _STORE_SHARED(y
->left
, z
);
459 _STORE_SHARED(y
->right
, z
);
460 rcu_rbtree_insert_fixup(root
, z
, rballoc
, rbfree
);
462 * Make sure to commit all _STORE_SHARED() for non-coherent caches.
470 * Transplant v into u position.
471 * Returns new copy of v.
473 static struct rcu_rbtree_node
*
474 rcu_rbtree_transplant(struct rcu_rbtree_node
**root
,
475 struct rcu_rbtree_node
*u
,
476 struct rcu_rbtree_node
*v
,
477 rcu_rbtree_alloc rballoc
,
478 rcu_rbtree_free rbfree
)
480 struct rcu_rbtree_node
*vc
;
482 if (v
!= &rcu_rbtree_nil
) {
486 /* Change vc parent pointer */
491 * Order stores to node copies (children/parents) before stores
492 * that will make the copies visible to the rest of the tree.
496 vc
= &rcu_rbtree_nil
;
499 /* Assign upper-level pointer to vc, replacing u. */
500 if (u
->p
== &rcu_rbtree_nil
)
501 _STORE_SHARED(*root
, vc
);
502 else if (u
== u
->p
->left
)
503 _STORE_SHARED(u
->p
->left
, vc
);
505 _STORE_SHARED(u
->p
->right
, vc
);
507 if (v
!= &rcu_rbtree_nil
) {
509 * The children pointers in vc are the same as v. We can
510 * therefore reparent v's children to vc safely.
512 if (vc
->right
!= &rcu_rbtree_nil
)
513 _STORE_SHARED(vc
->right
->p
, vc
);
514 if (vc
->left
!= &rcu_rbtree_nil
)
515 _STORE_SHARED(vc
->left
->p
, vc
);
517 defer_rcu(rbfree
, v
);
522 static void rcu_rbtree_remove_fixup(struct rcu_rbtree_node
**root
,
523 struct rcu_rbtree_node
*x
,
524 rcu_rbtree_alloc rballoc
,
525 rcu_rbtree_free rbfree
)
527 while (x
!= *root
&& x
->color
== COLOR_BLACK
) {
528 if (x
== x
->p
->left
) {
529 struct rcu_rbtree_node
*w
, *t
;
532 if (w
->color
== COLOR_RED
) {
533 w
->color
== COLOR_BLACK
;
534 x
->p
->color
= COLOR_RED
;
535 t
= left_rotate(root
, x
->p
, rballoc
, rbfree
);
536 assert(x
->p
->left
== t
->left
);
537 /* x is a left node, not copied by rotation */
540 if (w
->left
->color
== COLOR_BLACK
541 && w
->right
->color
== COLOR_BLACK
) {
542 w
->color
= COLOR_RED
;
545 if (w
->right
->color
== COLOR_BLACK
) {
546 w
->left
->color
= COLOR_BLACK
;
547 w
->color
= COLOR_RED
;
548 right_rotate(root
, w
, rballoc
, rbfree
);
551 w
->color
= x
->p
->color
;
552 x
->p
->color
= COLOR_BLACK
;
553 w
->right
->color
= COLOR_BLACK
;
554 left_rotate(root
, x
->p
, rballoc
, rbfree
);
558 struct rcu_rbtree_node
*w
, *t
;
561 if (w
->color
== COLOR_RED
) {
562 w
->color
== COLOR_BLACK
;
563 x
->p
->color
= COLOR_RED
;
564 t
= right_rotate(root
, x
->p
, rballoc
, rbfree
);
565 assert(x
->p
->right
== t
->right
);
566 /* x is a right node, not copied by rotation */
569 if (w
->right
->color
== COLOR_BLACK
570 && w
->left
->color
== COLOR_BLACK
) {
571 w
->color
= COLOR_RED
;
574 if (w
->left
->color
== COLOR_BLACK
) {
575 w
->right
->color
= COLOR_BLACK
;
576 w
->color
= COLOR_RED
;
577 left_rotate(root
, w
, rballoc
, rbfree
);
580 w
->color
= x
->p
->color
;
581 x
->p
->color
= COLOR_BLACK
;
582 w
->left
->color
= COLOR_BLACK
;
583 right_rotate(root
, x
->p
, rballoc
, rbfree
);
588 x
->color
= COLOR_BLACK
;
592 * Returns the new copy of y->right.
593 * Delete z. All non-copied children left/right positions are unchanged. */
594 static struct rcu_rbtree_node
*
595 rcu_rbtree_remove_nonil(struct rcu_rbtree_node
**root
,
596 struct rcu_rbtree_node
*z
,
597 struct rcu_rbtree_node
*y
,
598 rcu_rbtree_comp comp
,
599 rcu_rbtree_alloc rballoc
,
600 rcu_rbtree_free rbfree
)
602 struct rcu_rbtree_node
*x
, *xc
, *yc
;
606 if (x
!= &rcu_rbtree_nil
) {
610 xc
= &rcu_rbtree_nil
;
615 /* Update parent and children pointers within copies */
619 /* Transplant y->right (xc) into y, within copy */
621 /* But also change the right pointer of yc */
622 yc
->right
= z
->right
;
624 /* Transplant y into z, within copy */
628 yc
->color
= z
->color
;
631 * Order stores to node copies (children/parents) before stores that
632 * will make the copies visible to the rest of the tree.
636 /* Update external pointers */
639 /* Transplant y->right into y, external parent links */
641 /* Assign upper-level pointer to xc, replacing y. */
642 if (y
->p
== &rcu_rbtree_nil
)
643 _STORE_SHARED(*root
, xc
);
644 else if (y
== y
->p
->left
)
645 _STORE_SHARED(y
->p
->left
, xc
);
647 _STORE_SHARED(y
->p
->right
, xc
);
650 /* Transplant y into z, update external parent links */
651 if (z
->p
== &rcu_rbtree_nil
)
652 _STORE_SHARED(*root
, yc
);
653 else if (z
== z
->p
->left
)
654 _STORE_SHARED(z
->p
->left
, yc
);
656 _STORE_SHARED(z
->p
->right
, yc
);
658 if (x
!= &rcu_rbtree_nil
) {
659 /* Reparent xc's children to xc. */
660 _STORE_SHARED(xc
->right
->p
, xc
);
661 assert(yc
->right
== &rcu_rbtree_nil
662 || xc
->right
->pos
== IS_RIGHT
);
663 _STORE_SHARED(xc
->left
->p
, xc
);
664 assert(yc
->right
== &rcu_rbtree_nil
665 || xc
->left
->pos
== IS_LEFT
);
666 defer_rcu(rbfree
, x
);
669 /* Reparent yc's children to yc */
670 _STORE_SHARED(yc
->right
->p
, yc
);
671 assert(yc
->right
== &rcu_rbtree_nil
|| yc
->right
->pos
== IS_RIGHT
);
672 _STORE_SHARED(yc
->left
->p
, yc
);
673 assert(yc
->right
== &rcu_rbtree_nil
|| yc
->left
->pos
== IS_LEFT
);
674 defer_rcu(rbfree
, y
);
679 int rcu_rbtree_remove(struct rcu_rbtree_node
**root
,
680 struct rcu_rbtree_node
*z
,
681 rcu_rbtree_comp comp
,
682 rcu_rbtree_alloc rballoc
,
683 rcu_rbtree_free rbfree
)
685 struct rcu_rbtree_node
*x
, *y
;
686 unsigned int y_original_color
;
689 y_original_color
= y
->color
;
691 if (z
->left
== &rcu_rbtree_nil
) {
692 x
= rcu_rbtree_transplant(root
, z
, z
->right
, rballoc
, rbfree
);
693 } else if (z
->right
== &rcu_rbtree_nil
) {
694 x
= rcu_rbtree_transplant(root
, z
, z
->left
, rballoc
, rbfree
);
696 y
= rcu_rbtree_min(z
->right
, comp
);
697 y_original_color
= y
->color
;
698 x
= rcu_rbtree_remove_nonil(root
, z
, y
, comp
, rballoc
, rbfree
);
700 if (y_original_color
== COLOR_BLACK
)
701 rcu_rbtree_remove_fixup(root
, x
, rballoc
, rbfree
);
703 * Commit all _STORE_SHARED().