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 void set_decay(struct rcu_rbtree_node
*x
, struct rcu_rbtree_node
*xc
)
57 struct rcu_rbtree_node
*get_decay(struct rcu_rbtree_node
*x
)
65 struct rcu_rbtree_node
*is_decay(struct rcu_rbtree_node
*x
)
71 struct rcu_rbtree_node
*dup_decay_node(struct rcu_rbtree
*rbtree
,
72 struct rcu_rbtree_node
*x
)
74 struct rcu_rbtree_node
*xc
;
76 if (rcu_rbtree_is_nil(x
))
79 xc
= rbtree
->rballoc();
80 memcpy(xc
, x
, sizeof(struct rcu_rbtree_node
));
81 xc
->decay_next
= NULL
;
83 call_rcu(&x
->head
, rbtree
->rbfree
);
89 * Deal with memory allocation errors.
90 * Can be ensured by reserving a pool of memory entries before doing the
91 * insertion, which will have to be function of number of
92 * transplantations/rotations required for the operation.
96 void show_tree(struct rcu_rbtree
*rbtree
)
98 struct rcu_rbtree_node
*node
;
100 node
= rcu_rbtree_min(rbtree
, rbtree
->root
);
101 while (!rcu_rbtree_is_nil(node
)) {
102 assert(!is_decay(node
));
103 printf("{ 0x%lX p:%lX r:%lX l:%lX %s %s %s} ",
104 (unsigned long)node
->key
,
105 (unsigned long) node
->p
->key
,
106 (unsigned long) node
->right
->key
,
107 (unsigned long) node
->left
->key
,
108 node
->color
? "red" : "black",
109 node
->pos
? "right" : "left",
110 node
->nil
? "nil" : "");
111 node
= rcu_rbtree_next(rbtree
, node
);
117 struct rcu_rbtree_node
*make_nil(struct rcu_rbtree
*rbtree
)
119 return &rbtree
->nil_node
;
123 * Iterative rbtree search.
125 struct rcu_rbtree_node
* rcu_rbtree_search(struct rcu_rbtree
*rbtree
,
126 struct rcu_rbtree_node
*x
,
129 x
= rcu_dereference(x
);
131 while (!rcu_rbtree_is_nil(x
) && k
!= x
->key
) {
132 if (rbtree
->comp(k
, x
->key
) < 0)
133 x
= rcu_dereference(x
->left
);
135 x
= rcu_dereference(x
->right
);
140 struct rcu_rbtree_node
*rcu_rbtree_min(struct rcu_rbtree
*rbtree
,
141 struct rcu_rbtree_node
*x
)
143 struct rcu_rbtree_node
*xl
;
145 x
= rcu_dereference(x
);
147 if (rcu_rbtree_is_nil(x
))
150 while (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->left
)))
155 struct rcu_rbtree_node
*rcu_rbtree_max(struct rcu_rbtree
*rbtree
,
156 struct rcu_rbtree_node
*x
)
158 struct rcu_rbtree_node
*xr
;
160 x
= rcu_dereference(x
);
162 if (rcu_rbtree_is_nil(x
))
165 while (!rcu_rbtree_is_nil(xr
= rcu_dereference(x
->right
)))
172 * Updates should wait for a grace period between update of the
173 * redirect pointer and update of the parent child pointer. This is to make sure
174 * that no reference to the old entry exist.
178 * next and prev need to have mutex held to ensure that parent pointer is
181 struct rcu_rbtree_node
*rcu_rbtree_next(struct rcu_rbtree
*rbtree
,
182 struct rcu_rbtree_node
*x
)
184 struct rcu_rbtree_node
*xr
, *y
;
186 x
= rcu_dereference(x
);
188 if (!rcu_rbtree_is_nil(xr
= rcu_dereference(x
->right
)))
189 return rcu_rbtree_min(rbtree
, xr
);
190 y
= rcu_dereference(x
->p
);
191 while (!rcu_rbtree_is_nil(y
) && x
->pos
== IS_RIGHT
) {
193 y
= rcu_dereference(y
->p
);
198 struct rcu_rbtree_node
*rcu_rbtree_prev(struct rcu_rbtree
*rbtree
,
199 struct rcu_rbtree_node
*x
)
201 struct rcu_rbtree_node
*xl
, *y
;
203 x
= rcu_dereference(x
);
205 if (!rcu_rbtree_is_nil(xl
= rcu_dereference(x
->left
)))
206 return rcu_rbtree_min(rbtree
, xl
);
207 y
= rcu_dereference(x
->p
);
208 while (!rcu_rbtree_is_nil(y
) && x
->pos
== IS_LEFT
) {
210 y
= rcu_dereference(y
->p
);
216 * We have to ensure these assumptions are correct for prev/next
219 * with x being a right child, the assumption that:
221 * or if x is a left child, the assumption that:
224 * This explains why we have to allocate a vc copy of the node for left_rotate,
225 * right_rotate and transplant operations.
227 * We always ensure that the right/left child and correct parent is set in the
228 * node copies *before* we reparent the children and make the upper-level point
232 /* RCU: copy x and y, atomically point to new versions. GC old. */
233 /* Should be eventually followed by a cmm_smp_wmc() */
236 void left_rotate(struct rcu_rbtree
*rbtree
,
237 struct rcu_rbtree_node
*x
)
239 struct rcu_rbtree_node
*y
, *y_left
, *x_p
;
245 /* Now operate on new copy, decay old versions */
246 x
= dup_decay_node(rbtree
, x
);
247 y
= dup_decay_node(rbtree
, y
);
248 y_left
= dup_decay_node(rbtree
, y_left
);
253 /* Internal node modifications */
260 if (!rcu_rbtree_is_nil(y_left
)) {
262 y_left
->pos
= IS_RIGHT
;
265 cmm_smp_wmb(); /* write into node before publish */
267 /* External references update (visible by readers) */
268 if (rcu_rbtree_is_nil(x_p
))
269 _CMM_STORE_SHARED(rbtree
->root
, y
);
270 else if (x_pos
== IS_LEFT
)
271 _CMM_STORE_SHARED(x_p
->left
, y
);
273 _CMM_STORE_SHARED(x_p
->right
, y
);
275 /* Point children to new copy (parent only used by updates) */
276 if (!rcu_rbtree_is_nil(x
->left
))
278 if (!rcu_rbtree_is_nil(y
->right
))
282 assert(y
== rbtree
->root
|| y
->p
->left
== y
|| y
->p
->right
== y
);
283 assert(x
== rbtree
->root
|| x
->p
->left
== x
|| x
->p
->right
== x
);
284 assert(rcu_rbtree_is_nil(x
->right
) || x
->right
->p
== x
);
285 assert(rcu_rbtree_is_nil(x
->left
) || x
->left
->p
== x
);
286 assert(rcu_rbtree_is_nil(y
->right
) || y
->right
->p
== y
);
287 assert(rcu_rbtree_is_nil(y
->left
) || y
->left
->p
== y
);
288 assert(!is_decay(rbtree
->root
));
289 assert(!is_decay(x
));
290 assert(!is_decay(y
));
291 assert(!is_decay(x
->right
));
292 assert(!is_decay(x
->left
));
293 assert(!is_decay(y
->right
));
294 assert(!is_decay(y
->left
));
298 void right_rotate(struct rcu_rbtree
*rbtree
,
299 struct rcu_rbtree_node
*x
)
301 struct rcu_rbtree_node
*y
, *y_right
, *x_p
;
307 /* Now operate on new copy, decay old versions */
308 x
= dup_decay_node(rbtree
, x
);
309 y
= dup_decay_node(rbtree
, y
);
310 y_right
= dup_decay_node(rbtree
, y_right
);
315 /* Internal node modifications */
322 if (!rcu_rbtree_is_nil(y_right
)) {
324 y_right
->pos
= IS_LEFT
;
327 cmm_smp_wmb(); /* write into node before publish */
329 /* External references update (visible by readers) */
330 if (rcu_rbtree_is_nil(x_p
))
331 _CMM_STORE_SHARED(rbtree
->root
, y
);
332 else if (x_pos
== IS_RIGHT
)
333 _CMM_STORE_SHARED(x_p
->right
, y
);
335 _CMM_STORE_SHARED(x_p
->left
, y
);
337 /* Point children to new copy (parent only used by updates) */
338 if (!rcu_rbtree_is_nil(x
->right
))
340 if (!rcu_rbtree_is_nil(y
->left
))
344 assert(y
== rbtree
->root
|| y
->p
->right
== y
|| y
->p
->left
== y
);
345 assert(x
== rbtree
->root
|| x
->p
->right
== x
|| x
->p
->left
== x
);
346 assert(rcu_rbtree_is_nil(x
->left
) || x
->left
->p
== x
);
347 assert(rcu_rbtree_is_nil(x
->right
) || x
->right
->p
== x
);
348 assert(rcu_rbtree_is_nil(y
->left
) || y
->left
->p
== y
);
349 assert(rcu_rbtree_is_nil(y
->right
) || y
->right
->p
== y
);
350 assert(!is_decay(rbtree
->root
));
351 assert(!is_decay(x
));
352 assert(!is_decay(y
));
353 assert(!is_decay(x
->left
));
354 assert(!is_decay(x
->right
));
355 assert(!is_decay(y
->left
));
356 assert(!is_decay(y
->right
));
359 static void rcu_rbtree_insert_fixup(struct rcu_rbtree
*rbtree
,
360 struct rcu_rbtree_node
*z
)
362 struct rcu_rbtree_node
*y
;
364 dbg_printf("insert fixup %p\n", z
->key
);
365 assert(!is_decay(rbtree
->root
));
367 while (z
->p
->color
== COLOR_RED
) {
368 if (z
->p
== z
->p
->p
->left
) {
370 if (y
->color
== COLOR_RED
) {
371 z
->p
->color
= COLOR_BLACK
;
372 y
->color
= COLOR_BLACK
;
373 z
->p
->p
->color
= COLOR_RED
;
376 if (z
== z
->p
->right
) {
378 left_rotate(rbtree
, z
);
380 assert(!is_decay(rbtree
->root
));
382 z
->p
->color
= COLOR_BLACK
;
383 z
->p
->p
->color
= COLOR_RED
;
384 assert(!is_decay(z
));
385 assert(!is_decay(z
->p
));
386 assert(!is_decay(z
->p
->p
));
387 right_rotate(rbtree
, z
->p
->p
);
388 assert(!is_decay(z
));
389 assert(!is_decay(rbtree
->root
));
393 if (y
->color
== COLOR_RED
) {
394 z
->p
->color
= COLOR_BLACK
;
395 y
->color
= COLOR_BLACK
;
396 z
->p
->p
->color
= COLOR_RED
;
399 if (z
== z
->p
->left
) {
401 right_rotate(rbtree
, z
);
403 assert(!is_decay(rbtree
->root
));
405 z
->p
->color
= COLOR_BLACK
;
406 z
->p
->p
->color
= COLOR_RED
;
407 left_rotate(rbtree
, z
->p
->p
);
408 assert(!is_decay(z
));
409 assert(!is_decay(rbtree
->root
));
413 rbtree
->root
->color
= COLOR_BLACK
;
417 * rcu_rbtree_insert - Insert a node in the RCU rbtree
419 * Returns 0 on success, or < 0 on error.
421 int rcu_rbtree_insert(struct rcu_rbtree
*rbtree
,
422 struct rcu_rbtree_node
*z
)
424 struct rcu_rbtree_node
*x
, *y
;
426 dbg_printf("insert %p\n", z
->key
);
427 assert(!is_decay(rbtree
->root
));
429 y
= make_nil(rbtree
);
431 rbtree
->root
= make_nil(rbtree
);
433 while (!rcu_rbtree_is_nil(x
)) {
435 if (rbtree
->comp(z
->key
, x
->key
) < 0)
443 z
->left
= make_nil(rbtree
);
444 z
->right
= make_nil(rbtree
);
445 z
->color
= COLOR_RED
;
447 z
->decay_next
= NULL
;
449 if (rcu_rbtree_is_nil(y
))
450 z
->pos
= IS_RIGHT
; /* arbitrary for root node */
451 else if (rbtree
->comp(z
->key
, y
->key
) < 0)
457 * Order stores to z (children/parents) before stores that will make it
458 * visible to the rest of the tree.
462 if (rcu_rbtree_is_nil(y
))
463 _CMM_STORE_SHARED(rbtree
->root
, z
);
464 else if (rbtree
->comp(z
->key
, y
->key
) < 0)
465 _CMM_STORE_SHARED(y
->left
, z
);
467 _CMM_STORE_SHARED(y
->right
, z
);
468 rcu_rbtree_insert_fixup(rbtree
, z
);
470 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
479 * Transplant v into u position.
482 void rcu_rbtree_transplant(struct rcu_rbtree
*rbtree
,
483 struct rcu_rbtree_node
*u
,
484 struct rcu_rbtree_node
*v
)
486 dbg_printf("transplant %p\n", v
->key
);
488 if (!rcu_rbtree_is_nil(v
))
489 v
= dup_decay_node(rbtree
, v
);
491 if (rcu_rbtree_is_nil(u
->p
)) {
493 cmm_smp_wmb(); /* write into node before publish */
494 _CMM_STORE_SHARED(rbtree
->root
, v
);
495 } else if (u
== u
->p
->left
) {
498 cmm_smp_wmb(); /* write into node before publish */
499 _CMM_STORE_SHARED(u
->p
->left
, v
);
503 cmm_smp_wmb(); /* write into node before publish */
504 _CMM_STORE_SHARED(u
->p
->right
, v
);
506 /* Set children parent to new node (only used by updates) */
507 if (!rcu_rbtree_is_nil(v
)) {
511 assert(!is_decay(rbtree
->root
));
514 static void rcu_rbtree_remove_fixup(struct rcu_rbtree
*rbtree
,
515 struct rcu_rbtree_node
*x
)
517 dbg_printf("remove fixup %p\n", x
->key
);
519 while (x
!= rbtree
->root
&& x
->color
== COLOR_BLACK
) {
520 assert(!is_decay(x
->p
));
521 assert(!is_decay(x
->p
->left
));
522 if (x
== x
->p
->left
) {
523 struct rcu_rbtree_node
*w
;
527 if (w
->color
== COLOR_RED
) {
528 w
->color
= COLOR_BLACK
;
529 x
->p
->color
= COLOR_RED
;
530 left_rotate(rbtree
, x
->p
);
532 assert(!is_decay(rbtree
->root
));
535 if (w
->left
->color
== COLOR_BLACK
536 && w
->right
->color
== COLOR_BLACK
) {
537 w
->color
= COLOR_RED
;
539 assert(!is_decay(rbtree
->root
));
540 assert(!is_decay(x
));
542 if (w
->right
->color
== COLOR_BLACK
) {
543 w
->left
->color
= COLOR_BLACK
;
544 w
->color
= COLOR_RED
;
545 right_rotate(rbtree
, w
);
546 assert(!is_decay(rbtree
->root
));
550 w
->color
= x
->p
->color
;
551 x
->p
->color
= COLOR_BLACK
;
552 w
->right
->color
= COLOR_BLACK
;
553 left_rotate(rbtree
, x
->p
);
554 assert(!is_decay(rbtree
->root
));
558 struct rcu_rbtree_node
*w
;
562 if (w
->color
== COLOR_RED
) {
563 w
->color
= COLOR_BLACK
;
564 x
->p
->color
= COLOR_RED
;
565 right_rotate(rbtree
, x
->p
);
566 assert(!is_decay(rbtree
->root
));
570 if (w
->right
->color
== COLOR_BLACK
571 && w
->left
->color
== COLOR_BLACK
) {
572 w
->color
= COLOR_RED
;
574 assert(!is_decay(rbtree
->root
));
575 assert(!is_decay(x
));
577 if (w
->left
->color
== COLOR_BLACK
) {
578 w
->right
->color
= COLOR_BLACK
;
579 w
->color
= COLOR_RED
;
580 left_rotate(rbtree
, w
);
581 assert(!is_decay(rbtree
->root
));
585 w
->color
= x
->p
->color
;
586 x
->p
->color
= COLOR_BLACK
;
587 w
->left
->color
= COLOR_BLACK
;
588 right_rotate(rbtree
, x
->p
);
589 assert(!is_decay(rbtree
->root
));
594 x
->color
= COLOR_BLACK
;
598 * Delete z. All non-copied children left/right positions are unchanged.
601 void rcu_rbtree_remove_nonil(struct rcu_rbtree
*rbtree
,
602 struct rcu_rbtree_node
*z
,
603 struct rcu_rbtree_node
*y
)
605 struct rcu_rbtree_node
*x
;
607 dbg_printf("remove nonil %p\n", z
->key
);
610 assert(!is_decay(z
));
611 assert(!is_decay(y
));
612 assert(!is_decay(y
->right
));
613 assert(!is_decay(y
->p
));
615 assert(!is_decay(x
));
619 rcu_rbtree_transplant(rbtree
, y
, y
->right
);
620 assert(!is_decay(y
));
621 assert(!is_decay(z
));
622 assert(!is_decay(z
->right
));
626 rcu_rbtree_transplant(rbtree
, z
, y
);
628 assert(!is_decay(z
));
629 assert(!is_decay(z
->left
));
635 int rcu_rbtree_remove(struct rcu_rbtree
*rbtree
,
636 struct rcu_rbtree_node
*z
)
638 struct rcu_rbtree_node
*x
, *y
;
639 unsigned int y_original_color
;
641 assert(!is_decay(rbtree
->root
));
642 dbg_printf("remove %p\n", z
->key
);
645 assert(!is_decay(z
));
647 y_original_color
= y
->color
;
649 if (rcu_rbtree_is_nil(z
->left
)) {
650 rcu_rbtree_transplant(rbtree
, z
, z
->right
);
651 assert(!is_decay(z
));
652 x
= get_decay(z
->right
);
654 } else if (rcu_rbtree_is_nil(z
->right
)) {
655 rcu_rbtree_transplant(rbtree
, z
, z
->left
);
656 assert(!is_decay(z
));
657 x
= get_decay(z
->left
);
660 y
= rcu_rbtree_min(rbtree
, z
->right
);
661 assert(!is_decay(y
));
662 y_original_color
= y
->color
;
663 rcu_rbtree_remove_nonil(rbtree
, z
, y
);
664 x
= get_decay(y
->right
);
667 if (y_original_color
== COLOR_BLACK
)
668 rcu_rbtree_remove_fixup(rbtree
, x
);
671 * Commit all _CMM_STORE_SHARED().
This page took 0.04297 seconds and 5 git commands to generate.