Fix rbtree nil beta rotation
[userspace-rcu.git] / urcu-rbtree.c
CommitLineData
00131368
MD
1/*
2 * urcu-rbtree.c
3 *
4 * Userspace RCU library - Red-Black Tree
5 *
6 * Copyright (c) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
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.
12 *
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.
17 *
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
21 *
22 * Implementation of RCU-adapted data structures and operations based on the RB
23 * tree algorithms found in chapter 12 of:
24 *
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.
28 */
29
30#define _BSD_SOURCE
31#define _LGPL_SOURCE
32
33#include <stdio.h>
34#include <pthread.h>
f6e888c5 35#include <assert.h>
00131368
MD
36
37#include <urcu-rbtree.h>
38#include <urcu-pointer.h>
39
a4f1873b
MD
40#ifdef DEBUG
41#define dbg_printf(args...) printf(args)
42#else
43#define dbg_printf(args...)
44#endif
45
00131368
MD
46/*
47 * TODO
48 * Deal with memory allocation errors.
49 * Can be ensured by reserving a pool of memory entries before doing the
50 * insertion, which will have to be function of number of
51 * transplantations/rotations required for the operation.
52 */
53
8c91bac8
MD
54/* Sentinel (bottom nodes).
55 * Don't care about p, left, right, pos and key values */
db5b1669 56struct rcu_rbtree_node rcu_rbtree_nil = {
00131368
MD
57 .color = COLOR_BLACK,
58};
59
60/*
61 * Iterative rbtree search.
62 */
63struct rcu_rbtree_node* rcu_rbtree_search(struct rcu_rbtree_node *x,
64 void *k, rcu_rbtree_comp comp)
65{
66 x = rcu_dereference(x);
67
a23deda7 68 while (x != &rcu_rbtree_nil && k != x->key) {
00131368
MD
69 if (k < x->key)
70 x = rcu_dereference(x->left);
71 else
72 x = rcu_dereference(x->right);
73 }
74 return x;
75}
76
77struct rcu_rbtree_node *rcu_rbtree_min(struct rcu_rbtree_node *x,
78 rcu_rbtree_comp comp)
79{
80 struct rcu_rbtree_node *xl;
81
82 x = rcu_dereference(x);
83
a23deda7 84 while ((xl = rcu_dereference(x->left)) != &rcu_rbtree_nil)
00131368
MD
85 x = xl;
86 return x;
87}
88
89struct rcu_rbtree_node *rcu_rbtree_max(struct rcu_rbtree_node *x,
90 rcu_rbtree_comp comp)
91{
92 struct rcu_rbtree_node *xr;
93
94 x = rcu_dereference(x);
95
a23deda7 96 while ((xr = rcu_dereference(x->right)) != &rcu_rbtree_nil)
00131368
MD
97 x = xr;
98 return x;
99}
100
7ddb62c5
MD
101/*
102 * FIXME:
103 * Updates should wait for a grace period between update of the
104 * redirect pointer and update of the parent child pointer. This is to make sure
105 * that no reference to the old entry exist.
106 */
107
00131368
MD
108/*
109 * next and prev need to have mutex held to ensure that parent pointer is
110 * coherent.
111 */
112struct rcu_rbtree_node *rcu_rbtree_next(struct rcu_rbtree_node *x,
113 rcu_rbtree_comp comp)
114{
8c91bac8 115 struct rcu_rbtree_node *xr, *y, *yr;
00131368
MD
116
117 x = rcu_dereference(x);
118
a23deda7 119 if ((xr = rcu_dereference(x->right)) != &rcu_rbtree_nil)
00131368
MD
120 return rcu_rbtree_min(xr, comp);
121 y = rcu_dereference(x->p);
8c91bac8 122 while (y != &rcu_rbtree_nil && x->pos == IS_RIGHT) {
00131368
MD
123 x = y;
124 y = rcu_dereference(y->p);
125 }
126 return y;
127}
128
129struct rcu_rbtree_node *rcu_rbtree_prev(struct rcu_rbtree_node *x,
130 rcu_rbtree_comp comp)
131{
8c91bac8 132 struct rcu_rbtree_node *xl, *y, *yl;
00131368
MD
133
134 x = rcu_dereference(x);
135
a23deda7 136 if ((xl = rcu_dereference(x->left)) != &rcu_rbtree_nil)
9364f0c3 137 return rcu_rbtree_min(xl, comp);
00131368 138 y = rcu_dereference(x->p);
8c91bac8 139 while (y != &rcu_rbtree_nil && x->pos == IS_LEFT) {
00131368
MD
140 x = y;
141 y = rcu_dereference(y->p);
142 }
143 return y;
144}
145
146/*
147 * We have to ensure these assumptions are correct for prev/next
148 * traversal:
149 *
150 * with x being a right child, the assumption that:
151 * x->p->right == x
152 * or if x is a left child, the assumption that:
153 * x->p->left == x
154 *
155 * This explains why we have to allocate a vc copy of the node for left_rotate,
156 * right_rotate and transplant operations.
157 *
158 * We always ensure that the right/left child and correct parent is set in the
159 * node copies *before* we reparent the children and make the upper-level point
160 * to the copy.
161 */
162
163/* RCU: copy x and y, atomically point to new versions. GC old. */
164/* Should be eventually followed by a smp_wmc() */
8c91bac8
MD
165/* Returns the new x. Previous x->right references are changed to yc.
166 * Previous y->left->right is changed to bc. */
00131368
MD
167static struct rcu_rbtree_node *left_rotate(struct rcu_rbtree_node **root,
168 struct rcu_rbtree_node *x,
169 rcu_rbtree_alloc rballoc,
170 rcu_rbtree_free rbfree)
171{
8c91bac8 172 struct rcu_rbtree_node *xc, *y, *yc, *b, *bc;
00131368 173
a4f1873b
MD
174 dbg_printf("left rotate %p\n", x->key);
175
00131368
MD
176 y = x->right;
177
21cddea3
MD
178 if (x != &rcu_rbtree_nil) {
179 xc = rballoc();
180 *xc = *x;
8c91bac8 181 xc->pos = IS_LEFT;
a23deda7
MD
182 }
183
184 if (y != &rcu_rbtree_nil) {
185 yc = rballoc();
186 *yc = *y;
8c91bac8
MD
187 yc->pos = x->pos;
188 b = y->left;
189 } else {
190 b = &rcu_rbtree_nil;
191 }
192
193 if (b != &rcu_rbtree_nil) {
194 /* Beta position changes from left to right. */
195 bc = rballoc();
196 *bc = *b;
197 assert(b->pos == IS_LEFT);
198 bc->pos = IS_RIGHT;
a4f1873b
MD
199 } else
200 bc = &rcu_rbtree_nil;
a23deda7
MD
201
202 /* Modify children and parents in the node copies */
203 if (x != &rcu_rbtree_nil) {
8c91bac8 204 xc->right = bc;
21cddea3
MD
205 xc->p = yc;
206 } else
207 xc = &rcu_rbtree_nil;
208
209 if (y != &rcu_rbtree_nil) {
21cddea3
MD
210 yc->left = xc;
211 yc->p = x->p;
212 } else
213 yc = &rcu_rbtree_nil;
00131368
MD
214
215 /*
216 * Order stores to node copies (children/parents) before stores that
217 * will make the copies visible to the rest of the tree.
218 */
219 smp_wmb();
220
221 /* Make parents point to the copies */
db5b1669 222 if (x->p == &rcu_rbtree_nil)
00131368 223 _STORE_SHARED(*root, yc);
8c91bac8 224 else if (x->pos == IS_LEFT)
00131368
MD
225 _STORE_SHARED(x->p->left, yc);
226 else
227 _STORE_SHARED(x->p->right, yc);
228
229 /* Assign children parents to copies */
21cddea3 230 if (x != &rcu_rbtree_nil) {
8c91bac8 231 _STORE_SHARED(xc->left->p, xc); /* alpha stays left */
21cddea3
MD
232 defer_rcu(rbfree, x);
233 }
234 if (y != &rcu_rbtree_nil) {
8c91bac8 235 _STORE_SHARED(yc->right->p, yc);/* gamma stays right */
21cddea3
MD
236 defer_rcu(rbfree, y);
237 /* yc->left is xc, its parent is already set in node copy */
238 }
8c91bac8
MD
239 if (b != &rcu_rbtree_nil) {
240 _STORE_SHARED(bc->right->p, bc);
241 _STORE_SHARED(bc->left->p, bc);
242 defer_rcu(rbfree, b);
243 }
00131368
MD
244 return xc;
245}
246
247#if 0 /* orig */
248static void left_rotate(struct rcu_rbtree_node **root,
249 struct rcu_rbtree_node *x,
250 rcu_rbtree_alloc rballoc)
251{
252 struct rcu_rbtree_node *y;
253
254 y = x->right;
255 x->right = y->left;
db5b1669 256 if (y->left != &rcu_rbtree_nil)
00131368
MD
257 y->left->p = x;
258 y->p = x->p;
db5b1669 259 if (x->p == &rcu_rbtree_nil)
00131368
MD
260 *root = y;
261 else if (x == x->p->left)
262 x->p->left = y;
263 else
264 x->p->right = y;
265 y->left = x;
266 x->p = y;
267}
268#endif //0
269
270/* RCU: copy x and y, atomically point to new versions. GC old. */
271/* Should be eventually followed by a smp_wmc() */
8c91bac8
MD
272/* Returns the new y. Previous y->left references are changed to xc.
273 * Previous y->left->right is changed to bc */
00131368 274static struct rcu_rbtree_node *right_rotate(struct rcu_rbtree_node **root,
8c91bac8 275 struct rcu_rbtree_node *y,
00131368
MD
276 rcu_rbtree_alloc rballoc,
277 rcu_rbtree_free rbfree)
278{
8c91bac8 279 struct rcu_rbtree_node *x, *xc, *yc, *b, *bc;;
00131368 280
a4f1873b
MD
281 dbg_printf("right rotate %p\n", y->key);
282
8c91bac8 283 x = y->left;
00131368 284
21cddea3
MD
285 if (x != &rcu_rbtree_nil) {
286 xc = rballoc();
287 *xc = *x;
8c91bac8
MD
288 xc->pos = y->pos;
289 b = x->right;
290 } else {
291 b = &rcu_rbtree_nil;
a23deda7
MD
292 }
293
294 if (y != &rcu_rbtree_nil) {
295 yc = rballoc();
296 *yc = *y;
8c91bac8
MD
297 yc->pos = IS_RIGHT;
298 }
299
300 if (b != &rcu_rbtree_nil) {
301 /* Beta position changes from right to left. */
302 bc = rballoc();
303 *bc = *b;
304 assert(b->pos == IS_RIGHT);
305 bc->pos = IS_LEFT;
a4f1873b
MD
306 } else
307 bc = &rcu_rbtree_nil;
a23deda7
MD
308
309 /* Modify children and parents in the node copies */
310 if (x != &rcu_rbtree_nil) {
8c91bac8
MD
311 xc->right = yc;
312 xc->p = y->p;
21cddea3
MD
313 } else
314 xc = &rcu_rbtree_nil;
315
316 if (y != &rcu_rbtree_nil) {
8c91bac8
MD
317 yc->left = bc;
318 yc->p = xc;
21cddea3
MD
319 } else
320 yc = &rcu_rbtree_nil;
00131368
MD
321
322 /*
323 * Order stores to node copies (children/parents) before stores that
324 * will make the copies visible to the rest of the tree.
325 */
326 smp_wmb();
327
328 /* Make parents point to the copies */
8c91bac8
MD
329 if (y->p == &rcu_rbtree_nil)
330 _STORE_SHARED(*root, xc);
331 else if (y->pos == IS_RIGHT)
332 _STORE_SHARED(y->p->right, xc);
00131368 333 else
8c91bac8 334 _STORE_SHARED(y->p->left, xc);
00131368
MD
335
336 /* Assign children parents to copies */
21cddea3 337 if (x != &rcu_rbtree_nil) {
8c91bac8
MD
338 _STORE_SHARED(xc->left->p, xc); /* alpha stays left */
339 /* xc->right is yc, its parent is already set in node copy */
21cddea3
MD
340 defer_rcu(rbfree, x);
341 }
342 if (y != &rcu_rbtree_nil) {
8c91bac8 343 _STORE_SHARED(yc->right->p, yc);/* gamma stays right */
21cddea3 344 defer_rcu(rbfree, y);
21cddea3 345 }
8c91bac8
MD
346 if (b != &rcu_rbtree_nil) {
347 _STORE_SHARED(bc->right->p, bc);
348 _STORE_SHARED(bc->left->p, bc);
349 defer_rcu(rbfree, b);
350 }
351 return yc;
00131368
MD
352}
353
00131368
MD
354static void rcu_rbtree_insert_fixup(struct rcu_rbtree_node **root,
355 struct rcu_rbtree_node *z,
356 rcu_rbtree_alloc rballoc,
357 rcu_rbtree_free rbfree)
358{
359 struct rcu_rbtree_node *y;
360
a4f1873b
MD
361 dbg_printf("insert fixup %p\n", z->key);
362
00131368
MD
363 while (z->p->color == COLOR_RED) {
364 if (z->p == z->p->p->left) {
365 y = z->p->p->right;
366 if (y->color == COLOR_RED) {
367 z->p->color = COLOR_BLACK;
368 y->color = COLOR_BLACK;
369 z->p->p->color = COLOR_RED;
370 z = z->p->p;
371 } else {
372 if (z == z->p->right) {
373 z = z->p;
374 z = left_rotate(root, z,
375 rballoc, rbfree);
376 }
377 z->p->color = COLOR_BLACK;
378 z->p->p->color = COLOR_RED;
a23deda7 379 right_rotate(root, z->p->p, rballoc, rbfree);
00131368
MD
380 }
381 } else {
382 y = z->p->p->left;
383 if (y->color == COLOR_RED) {
384 z->p->color = COLOR_BLACK;
385 y->color = COLOR_BLACK;
386 z->p->p->color = COLOR_RED;
387 z = z->p->p;
388 } else {
389 if (z == z->p->left) {
390 z = z->p;
391 z = right_rotate(root, z,
392 rballoc, rbfree);
393 }
394 z->p->color = COLOR_BLACK;
395 z->p->p->color = COLOR_RED;
a23deda7 396 left_rotate(root, z->p->p, rballoc, rbfree);
00131368
MD
397 }
398 }
399 }
400 (*root)->color = COLOR_BLACK;
401}
402
403/*
404 * rcu_rbtree_insert - Insert a node in the RCU rbtree
405 *
406 * Returns 0 on success, or < 0 on error.
407 */
408int rcu_rbtree_insert(struct rcu_rbtree_node **root,
409 struct rcu_rbtree_node *z,
410 rcu_rbtree_comp comp,
411 rcu_rbtree_alloc rballoc,
412 rcu_rbtree_free rbfree)
413{
414 struct rcu_rbtree_node *x, *y;
415
a4f1873b
MD
416 dbg_printf("insert %p\n", z->key);
417
db5b1669 418 y = &rcu_rbtree_nil;
00131368
MD
419 x = *root;
420
db5b1669 421 while (x != &rcu_rbtree_nil) {
00131368
MD
422 y = x;
423 if (comp(z->key, x->key) < 0)
424 x = x->left;
425 else
426 x = x->right;
427 }
428
429 z->p = y;
db5b1669
MD
430 z->left = &rcu_rbtree_nil;
431 z->right = &rcu_rbtree_nil;
00131368 432 z->color = COLOR_RED;
8c91bac8
MD
433
434 if (y == &rcu_rbtree_nil)
435 z->pos = IS_RIGHT; /* arbitrary for root node */
436 else if (comp(z->key, y->key) < 0)
437 z->pos = IS_LEFT;
438 else
439 z->pos = IS_RIGHT;
00131368
MD
440
441 /*
442 * Order stores to z (children/parents) before stores that will make it
443 * visible to the rest of the tree.
444 */
445 smp_wmb();
446
db5b1669 447 if (y == &rcu_rbtree_nil)
00131368
MD
448 _STORE_SHARED(*root, z);
449 else if (comp(z->key, y->key) < 0)
450 _STORE_SHARED(y->left, z);
451 else
452 _STORE_SHARED(y->right, z);
453 rcu_rbtree_insert_fixup(root, z, rballoc, rbfree);
454 /*
455 * Make sure to commit all _STORE_SHARED() for non-coherent caches.
456 */
457 smp_wmc();
458
459 return 0;
460}
461
462/*
463 * Transplant v into u position.
464 * Returns new copy of v.
465 */
466static struct rcu_rbtree_node *
467rcu_rbtree_transplant(struct rcu_rbtree_node **root,
468 struct rcu_rbtree_node *u,
469 struct rcu_rbtree_node *v,
470 rcu_rbtree_alloc rballoc,
471 rcu_rbtree_free rbfree)
472{
473 struct rcu_rbtree_node *vc;
474
a4f1873b
MD
475 dbg_printf("transplant %p\n", v->key);
476
21cddea3
MD
477 if (v != &rcu_rbtree_nil) {
478 vc = rballoc();
479 *vc = *v;
00131368 480
21cddea3
MD
481 /* Change vc parent pointer */
482 vc->p = u->p;
8c91bac8 483 vc->pos = u->pos;
00131368 484
21cddea3
MD
485 /*
486 * Order stores to node copies (children/parents) before stores
487 * that will make the copies visible to the rest of the tree.
488 */
489 smp_wmb();
490 } else {
491 vc = &rcu_rbtree_nil;
492 }
00131368
MD
493
494 /* Assign upper-level pointer to vc, replacing u. */
db5b1669 495 if (u->p == &rcu_rbtree_nil)
00131368
MD
496 _STORE_SHARED(*root, vc);
497 else if (u == u->p->left)
498 _STORE_SHARED(u->p->left, vc);
499 else
500 _STORE_SHARED(u->p->right, vc);
501
21cddea3
MD
502 if (v != &rcu_rbtree_nil) {
503 /*
504 * The children pointers in vc are the same as v. We can
505 * therefore reparent v's children to vc safely.
506 */
8c91bac8
MD
507 if (vc->right != &rcu_rbtree_nil)
508 _STORE_SHARED(vc->right->p, vc);
509 if (vc->left != &rcu_rbtree_nil)
510 _STORE_SHARED(vc->left->p, vc);
00131368 511
21cddea3
MD
512 defer_rcu(rbfree, v);
513 }
00131368
MD
514 return vc;
515}
516
517static void rcu_rbtree_remove_fixup(struct rcu_rbtree_node **root,
518 struct rcu_rbtree_node *x,
519 rcu_rbtree_alloc rballoc,
520 rcu_rbtree_free rbfree)
521{
a4f1873b
MD
522 dbg_printf("remove fixup %p\n", x->key);
523
00131368
MD
524 while (x != *root && x->color == COLOR_BLACK) {
525 if (x == x->p->left) {
f6e888c5 526 struct rcu_rbtree_node *w, *t;
00131368
MD
527
528 w = x->p->right;
529 if (w->color == COLOR_RED) {
530 w->color == COLOR_BLACK;
531 x->p->color = COLOR_RED;
f6e888c5
MD
532 t = left_rotate(root, x->p, rballoc, rbfree);
533 assert(x->p->left == t->left);
00131368
MD
534 /* x is a left node, not copied by rotation */
535 w = x->p->right;
536 }
537 if (w->left->color == COLOR_BLACK
538 && w->right->color == COLOR_BLACK) {
539 w->color = COLOR_RED;
540 x = x->p;
541 } else {
542 if (w->right->color == COLOR_BLACK) {
543 w->left->color = COLOR_BLACK;
544 w->color = COLOR_RED;
545 right_rotate(root, w, rballoc, rbfree);
546 w = x->p->right;
547 }
548 w->color = x->p->color;
549 x->p->color = COLOR_BLACK;
550 w->right->color = COLOR_BLACK;
551 left_rotate(root, x->p, rballoc, rbfree);
552 x = *root;
553 }
554 } else {
8c91bac8 555 struct rcu_rbtree_node *w, *t;
00131368
MD
556
557 w = x->p->left;
558 if (w->color == COLOR_RED) {
559 w->color == COLOR_BLACK;
560 x->p->color = COLOR_RED;
8c91bac8
MD
561 t = right_rotate(root, x->p, rballoc, rbfree);
562 assert(x->p->right == t->right);
00131368
MD
563 /* x is a right node, not copied by rotation */
564 w = x->p->left;
565 }
566 if (w->right->color == COLOR_BLACK
567 && w->left->color == COLOR_BLACK) {
568 w->color = COLOR_RED;
569 x = x->p;
570 } else {
571 if (w->left->color == COLOR_BLACK) {
572 w->right->color = COLOR_BLACK;
573 w->color = COLOR_RED;
574 left_rotate(root, w, rballoc, rbfree);
575 w = x->p->left;
576 }
577 w->color = x->p->color;
578 x->p->color = COLOR_BLACK;
579 w->left->color = COLOR_BLACK;
580 right_rotate(root, x->p, rballoc, rbfree);
581 x = *root;
582 }
583 }
584 }
585 x->color = COLOR_BLACK;
586}
587
8c91bac8
MD
588/*
589 * Returns the new copy of y->right.
590 * Delete z. All non-copied children left/right positions are unchanged. */
00131368
MD
591static struct rcu_rbtree_node *
592rcu_rbtree_remove_nonil(struct rcu_rbtree_node **root,
593 struct rcu_rbtree_node *z,
594 struct rcu_rbtree_node *y,
595 rcu_rbtree_comp comp,
596 rcu_rbtree_alloc rballoc,
597 rcu_rbtree_free rbfree)
598{
599 struct rcu_rbtree_node *x, *xc, *yc;
600
a4f1873b
MD
601 dbg_printf("remove nonil %p\n", z->key);
602
00131368
MD
603 x = y->right;
604
a23deda7
MD
605 if (x != &rcu_rbtree_nil) {
606 xc = rballoc();
607 *xc = *x;
608 } else
609 xc = &rcu_rbtree_nil;
610
00131368 611 yc = rballoc();
00131368
MD
612 *yc = *y;
613
614 /* Update parent and children pointers within copies */
615 if (y->p == z)
616 xc->p = yc;
617 else {
618 /* Transplant y->right (xc) into y, within copy */
619 xc->p = y->p;
620 /* But also change the right pointer of yc */
621 yc->right = z->right;
622 }
623 /* Transplant y into z, within copy */
624 yc->p = z->p;
625
626 yc->left = z->left;
627 yc->color = z->color;
628
629 /*
630 * Order stores to node copies (children/parents) before stores that
631 * will make the copies visible to the rest of the tree.
632 */
633 smp_wmb();
634
635 /* Update external pointers */
636
637 if (y->p != z) {
638 /* Transplant y->right into y, external parent links */
639
640 /* Assign upper-level pointer to xc, replacing y. */
db5b1669 641 if (y->p == &rcu_rbtree_nil)
00131368
MD
642 _STORE_SHARED(*root, xc);
643 else if (y == y->p->left)
644 _STORE_SHARED(y->p->left, xc);
645 else
646 _STORE_SHARED(y->p->right, xc);
647 }
648
649 /* Transplant y into z, update external parent links */
db5b1669 650 if (z->p == &rcu_rbtree_nil)
00131368
MD
651 _STORE_SHARED(*root, yc);
652 else if (z == z->p->left)
653 _STORE_SHARED(z->p->left, yc);
654 else
655 _STORE_SHARED(z->p->right, yc);
656
a23deda7
MD
657 if (x != &rcu_rbtree_nil) {
658 /* Reparent xc's children to xc. */
659 _STORE_SHARED(xc->right->p, xc);
8c91bac8
MD
660 assert(yc->right == &rcu_rbtree_nil
661 || xc->right->pos == IS_RIGHT);
a23deda7 662 _STORE_SHARED(xc->left->p, xc);
8c91bac8
MD
663 assert(yc->right == &rcu_rbtree_nil
664 || xc->left->pos == IS_LEFT);
a23deda7
MD
665 defer_rcu(rbfree, x);
666 }
667
00131368
MD
668 /* Reparent yc's children to yc */
669 _STORE_SHARED(yc->right->p, yc);
8c91bac8 670 assert(yc->right == &rcu_rbtree_nil || yc->right->pos == IS_RIGHT);
00131368 671 _STORE_SHARED(yc->left->p, yc);
8c91bac8 672 assert(yc->right == &rcu_rbtree_nil || yc->left->pos == IS_LEFT);
00131368
MD
673 defer_rcu(rbfree, y);
674
675 return xc;
676}
677
678int rcu_rbtree_remove(struct rcu_rbtree_node **root,
679 struct rcu_rbtree_node *z,
680 rcu_rbtree_comp comp,
681 rcu_rbtree_alloc rballoc,
682 rcu_rbtree_free rbfree)
683{
684 struct rcu_rbtree_node *x, *y;
685 unsigned int y_original_color;
686
a4f1873b
MD
687 dbg_printf("remove %p\n", z->key);
688
00131368
MD
689 y = z;
690 y_original_color = y->color;
691
db5b1669 692 if (z->left == &rcu_rbtree_nil) {
00131368 693 x = rcu_rbtree_transplant(root, z, z->right, rballoc, rbfree);
db5b1669 694 } else if (z->right == &rcu_rbtree_nil) {
00131368
MD
695 x = rcu_rbtree_transplant(root, z, z->left, rballoc, rbfree);
696 } else {
697 y = rcu_rbtree_min(z->right, comp);
698 y_original_color = y->color;
699 x = rcu_rbtree_remove_nonil(root, z, y, comp, rballoc, rbfree);
700 }
701 if (y_original_color == COLOR_BLACK)
702 rcu_rbtree_remove_fixup(root, x, rballoc, rbfree);
703 /*
704 * Commit all _STORE_SHARED().
705 */
706 smp_wmc();
707
708 return 0;
709}
This page took 0.051928 seconds and 4 git commands to generate.