rcu rbtree: make rotation reader-aware
[userspace-rcu.git] / urcu-rbtree.c
CommitLineData
dff86257
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>
35#include <assert.h>
269a9ef6 36#include <string.h>
dff86257
MD
37
38#include <urcu/rcurbtree.h>
39#include <urcu-pointer.h>
c479601c 40#include <urcu-call-rcu.h>
dff86257
MD
41
42#define DEBUG
43
44#ifdef DEBUG
45#define dbg_printf(args...) printf(args)
46#else
47#define dbg_printf(args...)
48#endif
49
269a9ef6
MD
50static
51void set_decay(struct rcu_rbtree_node *x, struct rcu_rbtree_node *xc)
52{
53 x->decay_next = xc;
54}
55
56static
57struct rcu_rbtree_node *get_decay(struct rcu_rbtree_node *x)
58{
59 while (x->decay_next)
60 x = x->decay_next;
61 return x;
62}
63
64static
65struct rcu_rbtree_node *is_decay(struct rcu_rbtree_node *x)
66{
67 return x->decay_next;
68}
69
70static
71struct rcu_rbtree_node *dup_decay_node(struct rcu_rbtree *rbtree,
72 struct rcu_rbtree_node *x)
73{
74 struct rcu_rbtree_node *xc;
75
76 if (rcu_rbtree_is_nil(x))
77 return x;
78
79 xc = rbtree->rballoc();
80 memcpy(xc, x, sizeof(struct rcu_rbtree_node));
81 xc->decay_next = NULL;
82 set_decay(x, xc);
c479601c 83 call_rcu(&x->head, rbtree->rbfree);
269a9ef6
MD
84 return xc;
85}
86
dff86257
MD
87/*
88 * TODO
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.
93 */
94
95static
96void show_tree(struct rcu_rbtree *rbtree)
97{
98 struct rcu_rbtree_node *node;
99
100 node = rcu_rbtree_min(rbtree, rbtree->root);
101 while (!rcu_rbtree_is_nil(node)) {
269a9ef6 102 assert(!is_decay(node));
dff86257
MD
103 printf("{ 0x%lX p:%lX r:%lX l:%lX %s %s %s} ",
104 (unsigned long)node->key,
269a9ef6
MD
105 (unsigned long) node->p->key,
106 (unsigned long) node->right->key,
107 (unsigned long) node->left->key,
dff86257
MD
108 node->color ? "red" : "black",
109 node->pos ? "right" : "left",
110 node->nil ? "nil" : "");
111 node = rcu_rbtree_next(rbtree, node);
112 }
113 printf("\n");
114}
115
116static
117struct rcu_rbtree_node *make_nil(struct rcu_rbtree *rbtree)
118{
119 return &rbtree->nil_node;
120}
121
122/*
123 * Iterative rbtree search.
124 */
125struct rcu_rbtree_node* rcu_rbtree_search(struct rcu_rbtree *rbtree,
126 struct rcu_rbtree_node *x,
127 void *k)
128{
129 x = rcu_dereference(x);
130
131 while (!rcu_rbtree_is_nil(x) && k != x->key) {
132 if (rbtree->comp(k, x->key) < 0)
133 x = rcu_dereference(x->left);
134 else
135 x = rcu_dereference(x->right);
136 }
137 return x;
138}
139
140struct rcu_rbtree_node *rcu_rbtree_min(struct rcu_rbtree *rbtree,
141 struct rcu_rbtree_node *x)
142{
143 struct rcu_rbtree_node *xl;
144
145 x = rcu_dereference(x);
146
147 if (rcu_rbtree_is_nil(x))
148 return x;
149
150 while (!rcu_rbtree_is_nil(xl = rcu_dereference(x->left)))
151 x = xl;
152 return x;
153}
154
155struct rcu_rbtree_node *rcu_rbtree_max(struct rcu_rbtree *rbtree,
156 struct rcu_rbtree_node *x)
157{
158 struct rcu_rbtree_node *xr;
159
160 x = rcu_dereference(x);
161
162 if (rcu_rbtree_is_nil(x))
163 return x;
164
165 while (!rcu_rbtree_is_nil(xr = rcu_dereference(x->right)))
166 x = xr;
167 return x;
168}
169
170/*
171 * FIXME:
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.
175 */
176
177/*
178 * next and prev need to have mutex held to ensure that parent pointer is
179 * coherent.
180 */
181struct rcu_rbtree_node *rcu_rbtree_next(struct rcu_rbtree *rbtree,
182 struct rcu_rbtree_node *x)
183{
269a9ef6 184 struct rcu_rbtree_node *xr, *y;
dff86257
MD
185
186 x = rcu_dereference(x);
187
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) {
192 x = y;
193 y = rcu_dereference(y->p);
194 }
195 return y;
196}
197
198struct rcu_rbtree_node *rcu_rbtree_prev(struct rcu_rbtree *rbtree,
199 struct rcu_rbtree_node *x)
200{
269a9ef6 201 struct rcu_rbtree_node *xl, *y;
dff86257
MD
202
203 x = rcu_dereference(x);
204
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) {
209 x = y;
210 y = rcu_dereference(y->p);
211 }
212 return y;
213}
214
215/*
216 * We have to ensure these assumptions are correct for prev/next
217 * traversal:
218 *
219 * with x being a right child, the assumption that:
220 * x->p->right == x
221 * or if x is a left child, the assumption that:
222 * x->p->left == x
223 *
224 * This explains why we have to allocate a vc copy of the node for left_rotate,
225 * right_rotate and transplant operations.
226 *
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
229 * to the copy.
230 */
231
232/* RCU: copy x and y, atomically point to new versions. GC old. */
233/* Should be eventually followed by a cmm_smp_wmc() */
dff86257
MD
234
235static
269a9ef6
MD
236void left_rotate(struct rcu_rbtree *rbtree,
237 struct rcu_rbtree_node *x)
dff86257 238{
676dd8b6
MD
239 struct rcu_rbtree_node *y, *y_left, *x_p;
240 unsigned int x_pos;
dff86257 241
dff86257 242 y = x->right;
676dd8b6 243 y_left = y->left;
269a9ef6
MD
244
245 /* Now operate on new copy, decay old versions */
246 x = dup_decay_node(rbtree, x);
247 y = dup_decay_node(rbtree, y);
676dd8b6 248 y_left = dup_decay_node(rbtree, y_left);
269a9ef6 249
676dd8b6
MD
250 x_pos = x->pos;
251 x_p = x->p;
252
253 /* Internal node modifications */
254 x->right = y_left;
dff86257 255 y->p = x->p;
676dd8b6 256 y->pos = x->pos;
dff86257 257 x->pos = IS_LEFT;
676dd8b6 258 y->left = x;
dff86257 259 x->p = y;
676dd8b6
MD
260 if (!rcu_rbtree_is_nil(y_left)) {
261 y_left->p = x;
262 y_left->pos = IS_RIGHT;
263 }
264
265 cmm_smp_wmb(); /* write into node before publish */
266
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);
272 else
273 _CMM_STORE_SHARED(x_p->right, y);
274
275 /* Point children to new copy (parent only used by updates) */
269a9ef6
MD
276 if (!rcu_rbtree_is_nil(x->left))
277 x->left->p = x;
278 if (!rcu_rbtree_is_nil(y->right))
279 y->right->p = y;
280
281 /* Sanity checks */
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));
dff86257
MD
295}
296
297static
269a9ef6
MD
298void right_rotate(struct rcu_rbtree *rbtree,
299 struct rcu_rbtree_node *x)
dff86257 300{
676dd8b6
MD
301 struct rcu_rbtree_node *y, *y_right, *x_p;
302 unsigned int x_pos;
dff86257 303
dff86257 304 y = x->left;
676dd8b6 305 y_right = y->right;
269a9ef6
MD
306
307 /* Now operate on new copy, decay old versions */
308 x = dup_decay_node(rbtree, x);
309 y = dup_decay_node(rbtree, y);
676dd8b6 310 y_right = dup_decay_node(rbtree, y_right);
269a9ef6 311
676dd8b6
MD
312 x_pos = x->pos;
313 x_p = x->p;
314
315 /* Internal node modifications */
316 x->left = y_right;
dff86257 317 y->p = x->p;
676dd8b6 318 y->pos = x->pos;
dff86257 319 x->pos = IS_RIGHT;
676dd8b6 320 y->right = x;
dff86257 321 x->p = y;
676dd8b6
MD
322 if (!rcu_rbtree_is_nil(y_right)) {
323 y_right->p = x;
324 y_right->pos = IS_LEFT;
325 }
326
327 cmm_smp_wmb(); /* write into node before publish */
328
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);
334 else
335 _CMM_STORE_SHARED(x_p->left, y);
336
337 /* Point children to new copy (parent only used by updates) */
269a9ef6
MD
338 if (!rcu_rbtree_is_nil(x->right))
339 x->right->p = x;
340 if (!rcu_rbtree_is_nil(y->left))
341 y->left->p = y;
342
343 /* Sanity checks */
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));
dff86257
MD
357}
358
359static void rcu_rbtree_insert_fixup(struct rcu_rbtree *rbtree,
360 struct rcu_rbtree_node *z)
361{
362 struct rcu_rbtree_node *y;
363
364 dbg_printf("insert fixup %p\n", z->key);
269a9ef6 365 assert(!is_decay(rbtree->root));
dff86257
MD
366
367 while (z->p->color == COLOR_RED) {
368 if (z->p == z->p->p->left) {
369 y = z->p->p->right;
370 if (y->color == COLOR_RED) {
371 z->p->color = COLOR_BLACK;
372 y->color = COLOR_BLACK;
373 z->p->p->color = COLOR_RED;
374 z = z->p->p;
375 } else {
376 if (z == z->p->right) {
377 z = z->p;
378 left_rotate(rbtree, z);
269a9ef6
MD
379 z = get_decay(z);
380 assert(!is_decay(rbtree->root));
dff86257
MD
381 }
382 z->p->color = COLOR_BLACK;
383 z->p->p->color = COLOR_RED;
269a9ef6
MD
384 assert(!is_decay(z));
385 assert(!is_decay(z->p));
386 assert(!is_decay(z->p->p));
dff86257 387 right_rotate(rbtree, z->p->p);
269a9ef6
MD
388 assert(!is_decay(z));
389 assert(!is_decay(rbtree->root));
dff86257
MD
390 }
391 } else {
392 y = z->p->p->left;
393 if (y->color == COLOR_RED) {
394 z->p->color = COLOR_BLACK;
395 y->color = COLOR_BLACK;
396 z->p->p->color = COLOR_RED;
397 z = z->p->p;
398 } else {
399 if (z == z->p->left) {
400 z = z->p;
401 right_rotate(rbtree, z);
269a9ef6
MD
402 z = get_decay(z);
403 assert(!is_decay(rbtree->root));
dff86257
MD
404 }
405 z->p->color = COLOR_BLACK;
406 z->p->p->color = COLOR_RED;
407 left_rotate(rbtree, z->p->p);
269a9ef6
MD
408 assert(!is_decay(z));
409 assert(!is_decay(rbtree->root));
dff86257
MD
410 }
411 }
412 }
413 rbtree->root->color = COLOR_BLACK;
414}
415
416/*
417 * rcu_rbtree_insert - Insert a node in the RCU rbtree
418 *
419 * Returns 0 on success, or < 0 on error.
420 */
421int rcu_rbtree_insert(struct rcu_rbtree *rbtree,
422 struct rcu_rbtree_node *z)
423{
424 struct rcu_rbtree_node *x, *y;
425
426 dbg_printf("insert %p\n", z->key);
269a9ef6 427 assert(!is_decay(rbtree->root));
dff86257
MD
428
429 y = make_nil(rbtree);
430 if (!rbtree->root)
431 rbtree->root = make_nil(rbtree);
432 x = rbtree->root;
433 while (!rcu_rbtree_is_nil(x)) {
434 y = x;
435 if (rbtree->comp(z->key, x->key) < 0)
436 x = x->left;
437 else
438 x = x->right;
439 }
440
441 z->p = y;
442
443 z->left = make_nil(rbtree);
444 z->right = make_nil(rbtree);
445 z->color = COLOR_RED;
446 z->nil = 0;
269a9ef6 447 z->decay_next = NULL;
dff86257
MD
448
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)
452 z->pos = IS_LEFT;
453 else
454 z->pos = IS_RIGHT;
455
456 /*
457 * Order stores to z (children/parents) before stores that will make it
458 * visible to the rest of the tree.
459 */
460 cmm_smp_wmb();
461
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);
466 else
467 _CMM_STORE_SHARED(y->right, z);
468 rcu_rbtree_insert_fixup(rbtree, z);
469 /*
470 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
471 */
472 cmm_smp_wmc();
473 show_tree(rbtree);
474
475 return 0;
476}
477
478/*
479 * Transplant v into u position.
dff86257 480 */
269a9ef6
MD
481static
482void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
483 struct rcu_rbtree_node *u,
484 struct rcu_rbtree_node *v)
dff86257 485{
dff86257
MD
486 dbg_printf("transplant %p\n", v->key);
487
c479601c
MD
488 if (!rcu_rbtree_is_nil(v))
489 v = dup_decay_node(rbtree, v);
490
491 if (rcu_rbtree_is_nil(u->p)) {
492 v->p = 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) {
dff86257 496 v->pos = IS_LEFT;
c479601c
MD
497 v->p = u->p;
498 cmm_smp_wmb(); /* write into node before publish */
499 _CMM_STORE_SHARED(u->p->left, v);
dff86257 500 } else {
dff86257 501 v->pos = IS_RIGHT;
c479601c
MD
502 v->p = u->p;
503 cmm_smp_wmb(); /* write into node before publish */
504 _CMM_STORE_SHARED(u->p->right, v);
505 }
676dd8b6 506 /* Set children parent to new node (only used by updates) */
c479601c
MD
507 if (!rcu_rbtree_is_nil(v)) {
508 v->right->p = v;
509 v->left->p = v;
dff86257 510 }
269a9ef6 511 assert(!is_decay(rbtree->root));
dff86257
MD
512}
513
514static void rcu_rbtree_remove_fixup(struct rcu_rbtree *rbtree,
515 struct rcu_rbtree_node *x)
516{
517 dbg_printf("remove fixup %p\n", x->key);
518
519 while (x != rbtree->root && x->color == COLOR_BLACK) {
c479601c
MD
520 assert(!is_decay(x->p));
521 assert(!is_decay(x->p->left));
dff86257 522 if (x == x->p->left) {
269a9ef6 523 struct rcu_rbtree_node *w;
dff86257
MD
524
525 w = x->p->right;
526
527 if (w->color == COLOR_RED) {
269a9ef6 528 w->color = COLOR_BLACK;
dff86257 529 x->p->color = COLOR_RED;
269a9ef6
MD
530 left_rotate(rbtree, x->p);
531 x = get_decay(x);
532 assert(!is_decay(rbtree->root));
dff86257
MD
533 w = x->p->right;
534 }
535 if (w->left->color == COLOR_BLACK
536 && w->right->color == COLOR_BLACK) {
537 w->color = COLOR_RED;
538 x = x->p;
c479601c
MD
539 assert(!is_decay(rbtree->root));
540 assert(!is_decay(x));
dff86257
MD
541 } else {
542 if (w->right->color == COLOR_BLACK) {
543 w->left->color = COLOR_BLACK;
544 w->color = COLOR_RED;
545 right_rotate(rbtree, w);
c479601c 546 assert(!is_decay(rbtree->root));
269a9ef6 547 x = get_decay(x);
dff86257
MD
548 w = x->p->right;
549 }
550 w->color = x->p->color;
551 x->p->color = COLOR_BLACK;
552 w->right->color = COLOR_BLACK;
553 left_rotate(rbtree, x->p);
269a9ef6 554 assert(!is_decay(rbtree->root));
dff86257
MD
555 x = rbtree->root;
556 }
557 } else {
269a9ef6 558 struct rcu_rbtree_node *w;
dff86257
MD
559
560 w = x->p->left;
561
562 if (w->color == COLOR_RED) {
269a9ef6 563 w->color = COLOR_BLACK;
dff86257 564 x->p->color = COLOR_RED;
269a9ef6 565 right_rotate(rbtree, x->p);
c479601c 566 assert(!is_decay(rbtree->root));
269a9ef6 567 x = get_decay(x);
dff86257
MD
568 w = x->p->left;
569 }
570 if (w->right->color == COLOR_BLACK
571 && w->left->color == COLOR_BLACK) {
572 w->color = COLOR_RED;
573 x = x->p;
c479601c
MD
574 assert(!is_decay(rbtree->root));
575 assert(!is_decay(x));
dff86257
MD
576 } else {
577 if (w->left->color == COLOR_BLACK) {
578 w->right->color = COLOR_BLACK;
579 w->color = COLOR_RED;
580 left_rotate(rbtree, w);
269a9ef6
MD
581 assert(!is_decay(rbtree->root));
582 x = get_decay(x);
dff86257
MD
583 w = x->p->left;
584 }
585 w->color = x->p->color;
586 x->p->color = COLOR_BLACK;
587 w->left->color = COLOR_BLACK;
588 right_rotate(rbtree, x->p);
c479601c 589 assert(!is_decay(rbtree->root));
dff86257
MD
590 x = rbtree->root;
591 }
592 }
593 }
594 x->color = COLOR_BLACK;
595}
596
597/*
269a9ef6
MD
598 * Delete z. All non-copied children left/right positions are unchanged.
599 */
600static
601void rcu_rbtree_remove_nonil(struct rcu_rbtree *rbtree,
602 struct rcu_rbtree_node *z,
603 struct rcu_rbtree_node *y)
dff86257 604{
269a9ef6 605 struct rcu_rbtree_node *x;
dff86257
MD
606
607 dbg_printf("remove nonil %p\n", z->key);
608 show_tree(rbtree);
609
c479601c
MD
610 assert(!is_decay(z));
611 assert(!is_decay(y));
612 assert(!is_decay(y->right));
613 assert(!is_decay(y->p));
dff86257 614 x = y->right;
c479601c 615 assert(!is_decay(x));
dff86257
MD
616 if (y->p == z)
617 x->p = y;
618 else {
619 rcu_rbtree_transplant(rbtree, y, y->right);
269a9ef6
MD
620 assert(!is_decay(y));
621 assert(!is_decay(z));
c479601c 622 assert(!is_decay(z->right));
dff86257
MD
623 y->right = z->right;
624 y->right->p = y;
625 }
626 rcu_rbtree_transplant(rbtree, z, y);
c479601c 627 y = get_decay(y);
269a9ef6 628 assert(!is_decay(z));
c479601c 629 assert(!is_decay(z->left));
dff86257
MD
630 y->left = z->left;
631 y->left->p = y;
632 y->color = z->color;
dff86257
MD
633}
634
635int rcu_rbtree_remove(struct rcu_rbtree *rbtree,
636 struct rcu_rbtree_node *z)
637{
638 struct rcu_rbtree_node *x, *y;
639 unsigned int y_original_color;
640
269a9ef6 641 assert(!is_decay(rbtree->root));
dff86257
MD
642 dbg_printf("remove %p\n", z->key);
643 show_tree(rbtree);
644
c479601c 645 assert(!is_decay(z));
dff86257
MD
646 y = z;
647 y_original_color = y->color;
648
649 if (rcu_rbtree_is_nil(z->left)) {
269a9ef6
MD
650 rcu_rbtree_transplant(rbtree, z, z->right);
651 assert(!is_decay(z));
c479601c 652 x = get_decay(z->right);
dff86257
MD
653 show_tree(rbtree);
654 } else if (rcu_rbtree_is_nil(z->right)) {
269a9ef6
MD
655 rcu_rbtree_transplant(rbtree, z, z->left);
656 assert(!is_decay(z));
c479601c 657 x = get_decay(z->left);
dff86257
MD
658 show_tree(rbtree);
659 } else {
660 y = rcu_rbtree_min(rbtree, z->right);
c479601c 661 assert(!is_decay(y));
dff86257 662 y_original_color = y->color;
269a9ef6 663 rcu_rbtree_remove_nonil(rbtree, z, y);
c479601c 664 x = get_decay(y->right);
dff86257
MD
665 show_tree(rbtree);
666 }
667 if (y_original_color == COLOR_BLACK)
668 rcu_rbtree_remove_fixup(rbtree, x);
669 show_tree(rbtree);
670 /*
671 * Commit all _CMM_STORE_SHARED().
672 */
673 cmm_smp_wmc();
674
675 return 0;
676}
This page took 0.065508 seconds and 4 git commands to generate.