rcurbtree: update non-rcu test functions for range-awareness
[urcu.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>
230dd288 37#include <unistd.h>
8f354bc4 38#include <errno.h>
dff86257
MD
39
40#include <urcu/rcurbtree.h>
41#include <urcu-pointer.h>
c479601c 42#include <urcu-call-rcu.h>
dca45c9f 43#include <urcu/compiler.h>
dff86257 44
ae46d4ae
MD
45/*
46 * Explanation of next/prev walk coherency and search coherency when
47 * performed concurrently with updates.
48 *
49 * next/prev walk coherency with respect to concurrent updates:
50 *
51 * There are 3 scenarios for which we need to model and validate this:
52 * rotation, transplant and "teleportation" (the latter being a remote
53 * transplant in a remove non-nil case).
54 *
55 * - rotation left (right is symmetric)
56 * xl and yr point to the same parent nodes before/after left
57 * rotation. yll and ylr also point to the same parent node
58 * before/after left rotation.
59 * As we are copying x, y and yl (the 3 nodes which parent/child
60 * relationship are changed) to "new" version of this node cluster,
61 * all external references to the cluster either point to the old
62 * cluster or the new one. If we take this cluster as a "black box"
63 * from the point of view of next/prev traversal, all we have to
64 * ensure is that the old and the new cluster behave in the exact same
65 * way with respect to traversal order.
66 *
67 * - transplant
68 * In this operation, we transplant a copy of "v" into its parent
69 * location (u), thus replacing it. The children of "v", vl and vr,
70 * still point to v (new version) after the transplant, so it does not
71 * change the behavior when considering the next/prev traversal. "v"
72 * being copied to a new version ensures that the parent pointers of v
73 * are pointing to its new parent (parent of u) before it is published
74 * to readers (by setting the child pointer of u's parent to the new
75 * copy of v).
76 *
77 * - teleportation
78 * This one is probably the most tricky and will require some ascii
79 * art to explain.
80 *
81 * We want to remove z from this tree:
82 *
83 * zp
84 * \
85 * z
86 * / \
87 * zl zr
88 * /
89 * a
90 * / \
91 * b ar
92 * / \
93 * y br
94 * \
95 * yr
96 * / \
97 * yrl yrr
98 *
99 * What we are going to do is to "teleport" y into z's location,
100 * reparenting yr to b. We are taking care to create a new cluster
101 * copy that is isolated from any reader. We will represent the new
102 * members of the cluster with capital letters.
103 *
104 * zp
105 * \
106 * Y
107 * / \
108 * zl ZR
109 * /
110 * A
111 * / \
112 * B ar
113 * / \
114 * YR br
115 * / \
116 * yrl yrr
117 *
118 * In this transient state, we notice that the pointers within the
119 * cluster all point to the new cluster nodes, and they point to the
120 * correct external nodes. However, no external pointer point to the
121 * cluster (yet). The first pointer to point to this cluster will be
122 * "zp->right". It will therefore make the cluster visible for search.
123 *
124 * In this intermediate state, we can walk through the new cluster
125 * when coming from the top (in a next/prev traversal), but can come
126 * back to the old cluster when going back up from the children nodes.
127 * All we have to ensure is that the two clusters, taken as a black
128 * box from a next/prev traversal perspective, yield to the exact same
129 * result.
130 *
131 * Search coherency with concurrent updates:
132 *
133 * Simple "search" (only going down the tree) is also handled by this
134 * cluster scheme. The explanation is a subset of the prev/next
135 * explanation, where we don't have to care about the intermediate
136 * stages where the children point to the old cluster, because we only
137 * ever use the top level pointers to go down into the children nodes,
138 * we never go back up. So by simply making sure that all the cluster
139 * internal nodes pointers are setup correctly before making the
140 * cluster visible to the readers (by setting the parent pointer to
141 * the topmost new node in the cluster), we are sure that readers will
142 * see a coherent view of the cluster at all times.
143 */
144
dff86257
MD
145#ifdef DEBUG
146#define dbg_printf(args...) printf(args)
9c161ee1 147#define dbg_usleep(usecs) usleep(usecs)
dff86257
MD
148#else
149#define dbg_printf(args...)
9c161ee1 150#define dbg_usleep(usecs)
dff86257
MD
151#endif
152
6daf6090
MD
153/*
154 * Undefine this to enable the non-RCU rotate and transplant functions
2abaffb0
MD
155 * (for debugging). Note that these versions don't support the tree
156 * max_end updates, so lookups must be performed with
157 * rcu_rbtree_search_begin_key when using this debug facility.
6daf6090 158 */
dbe4ae98
MD
159#define RBTREE_RCU_SUPPORT_ROTATE_LEFT
160#define RBTREE_RCU_SUPPORT_ROTATE_RIGHT
6daf6090 161#define RBTREE_RCU_SUPPORT_TRANSPLANT
c2ceb27c 162#define RBTREE_RCU_SUPPORT
6daf6090 163
1444707c
MD
164/*
165 * Add internal mutex locking within the RBTree, for debugging. Enable this
166 * define and add mutexes to RCU readers to debug races with with rotation or
167 * transplant.
168 */
169/* #define RBTREE_INTERNAL_LOCKING */
170
171#ifdef RBTREE_INTERNAL_LOCKING
230dd288
MD
172static pthread_mutex_t test_mutex = PTHREAD_MUTEX_INITIALIZER;
173static pthread_mutex_t outer_mutex = PTHREAD_MUTEX_INITIALIZER;
174
175static
176void lock_outer_mutex(void)
177{
178 pthread_mutex_lock(&outer_mutex);
179}
180
181static
182void unlock_outer_mutex(void)
183{
184 pthread_mutex_unlock(&outer_mutex);
185}
186
187static
188void lock_test_mutex(void)
189{
190 pthread_mutex_lock(&test_mutex);
191}
192
193static
194void unlock_test_mutex(void)
195{
196 pthread_mutex_unlock(&test_mutex);
197}
1444707c
MD
198#else
199static
200void lock_outer_mutex(void)
201{
202}
203
204static
205void unlock_outer_mutex(void)
206{
207}
208
209static
210void lock_test_mutex(void)
211{
212}
213
214static
215void unlock_test_mutex(void)
216{
217}
230dd288
MD
218#endif
219
7ba89e62
MD
220static
221void set_parent(struct rcu_rbtree_node *node,
222 struct rcu_rbtree_node *parent,
223 unsigned int pos)
224{
9606ca85 225 _CMM_STORE_SHARED(node->parent, ((unsigned long) parent) | pos);
7ba89e62
MD
226}
227
228static
229struct rcu_rbtree_node *get_parent(struct rcu_rbtree_node *node)
230{
231 return (struct rcu_rbtree_node *) (node->parent & ~1UL);
232}
233
234static
235unsigned int get_pos(struct rcu_rbtree_node *node)
236{
237 return (unsigned int) (node->parent & 1UL);
238}
239
240static
241struct rcu_rbtree_node *get_parent_and_pos(struct rcu_rbtree_node *node,
242 unsigned int *pos)
243{
244 unsigned long parent_pos = rcu_dereference(node->parent);
245
246 *pos = (unsigned int) (parent_pos & 1UL);
247 return (struct rcu_rbtree_node *) (parent_pos & ~1UL);
248}
249
269a9ef6
MD
250static
251void set_decay(struct rcu_rbtree_node *x, struct rcu_rbtree_node *xc)
252{
253 x->decay_next = xc;
254}
255
256static
257struct rcu_rbtree_node *get_decay(struct rcu_rbtree_node *x)
258{
dbe4ae98
MD
259 if (!x)
260 return NULL;
269a9ef6
MD
261 while (x->decay_next)
262 x = x->decay_next;
263 return x;
264}
265
266static
267struct rcu_rbtree_node *is_decay(struct rcu_rbtree_node *x)
268{
269 return x->decay_next;
270}
271
3c672595 272static
8f354bc4
MD
273struct rcu_rbtree_node *_rcu_rbtree_alloc_node(struct rcu_rbtree *rbtree)
274{
275 return rbtree->rballoc(sizeof(struct rcu_rbtree_node));
276}
277
278static
279void _rcu_rbtree_free_node(struct rcu_head *head)
3c672595
MD
280{
281 struct rcu_rbtree_node *node =
282 caa_container_of(head, struct rcu_rbtree_node, head);
283 node->rbtree->rbfree(node);
284}
285
c2ceb27c
MD
286#ifdef RBTREE_RCU_SUPPORT
287
269a9ef6
MD
288static
289struct rcu_rbtree_node *dup_decay_node(struct rcu_rbtree *rbtree,
290 struct rcu_rbtree_node *x)
291{
292 struct rcu_rbtree_node *xc;
293
8ded5fe9 294 if (rcu_rbtree_is_nil(rbtree, x))
269a9ef6
MD
295 return x;
296
8f354bc4 297 xc = _rcu_rbtree_alloc_node(rbtree);
3c672595 298 memcpy(xc, x, sizeof(*xc));
269a9ef6
MD
299 xc->decay_next = NULL;
300 set_decay(x, xc);
1cdd423d 301 rbtree->call_rcu(&x->head, _rcu_rbtree_free_node);
269a9ef6
MD
302 return xc;
303}
304
c2ceb27c
MD
305#else /* RBTREE_RCU_SUPPORT */
306
307static
308struct rcu_rbtree_node *dup_decay_node(struct rcu_rbtree *rbtree,
309 struct rcu_rbtree_node *x)
310{
311 return x;
312}
313
314#endif
315
dca45c9f
MD
316/*
317 * Info for range lookups:
318 * Range lookup information is only valid when used when searching for
319 * ranges. It should never be used in next/prev traversal because the
320 * pointers to parents are not in sync with the parent vision of the
321 * children range.
322 */
323static
a84e8c8e
MD
324void set_left(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node,
325 struct rcu_rbtree_node *left)
dca45c9f 326{
dca45c9f 327 node->_left = left;
dca45c9f
MD
328}
329
330static
a84e8c8e
MD
331void set_right(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node,
332 struct rcu_rbtree_node *right)
dca45c9f 333{
dca45c9f 334 node->_right = right;
dca45c9f
MD
335}
336
66b64c35
MD
337static
338void *calculate_node_max_end(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node)
339{
340 void *max_end;
341
342 max_end = node->end;
343 if (!rcu_rbtree_is_nil(rbtree, node->_right)) {
344 if (rbtree->comp(max_end, node->_right->max_end) < 0)
345 max_end = node->_right->max_end;
346 }
347 if (!rcu_rbtree_is_nil(rbtree, node->_left)) {
348 if (rbtree->comp(max_end, node->_left->max_end) < 0)
349 max_end = node->_left->max_end;
350 }
351 return max_end;
352}
353
dff86257
MD
354/*
355 * TODO
356 * Deal with memory allocation errors.
357 * Can be ensured by reserving a pool of memory entries before doing the
358 * insertion, which will have to be function of number of
e20fb727
MD
359 * transplantations/rotations required for the operation (which is a
360 * multiple of the tree height).
dff86257
MD
361 */
362
5d2c985d 363#ifdef DEBUG
dff86257
MD
364static
365void show_tree(struct rcu_rbtree *rbtree)
366{
367 struct rcu_rbtree_node *node;
368
369 node = rcu_rbtree_min(rbtree, rbtree->root);
8ded5fe9 370 while (!rcu_rbtree_is_nil(rbtree, node)) {
269a9ef6 371 assert(!is_decay(node));
fcb4eea8 372 printf("{ b:%lX e:%lX pb: %lX r:%lX l:%lX %s %s %s} ",
3366b9c0
MD
373 (unsigned long) node->begin,
374 (unsigned long) node->end,
375 (unsigned long) get_parent(node)->begin,
fcb4eea8
MD
376 (unsigned long) node->_right->begin,
377 (unsigned long) node->_left->begin,
dff86257 378 node->color ? "red" : "black",
7ba89e62 379 get_pos(node) ? "right" : "left",
a84e8c8e 380 rcu_rbtree_is_nil(rbtree, node) ? "nil" : "");
dff86257
MD
381 node = rcu_rbtree_next(rbtree, node);
382 }
383 printf("\n");
384}
66b64c35
MD
385
386#define check_max_end(rbtree, x) \
387 do { \
388 if (rcu_rbtree_is_nil(rbtree, x)) \
389 break; \
390 assert(rbtree->comp(x->max_end, \
391 calculate_node_max_end(rbtree, x)) == 0); \
392 } while (0)
393
5d2c985d
MD
394#else /* DEBUG */
395static
396void show_tree(struct rcu_rbtree *rbtree)
397{
398}
66b64c35
MD
399
400static
401void check_max_end(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *x)
402{
403}
5d2c985d 404#endif /* DEBUG */
dff86257
MD
405
406static
407struct rcu_rbtree_node *make_nil(struct rcu_rbtree *rbtree)
408{
409 return &rbtree->nil_node;
410}
411
412/*
413 * Iterative rbtree search.
414 */
00539351 415struct rcu_rbtree_node *rcu_rbtree_search(struct rcu_rbtree *rbtree,
66b64c35
MD
416 struct rcu_rbtree_node *x,
417 void *point)
418{
419 struct rcu_rbtree_node *xl;
420
421 dbg_printf("searching point 0x%lx\n", (unsigned long) point);
422 x = rcu_dereference(x);
423
424 while (!rcu_rbtree_is_nil(rbtree, x)) {
425 dbg_usleep(10);
426 xl = rcu_dereference(x->_left);
427 dbg_printf("search x %lx x_end %lx x_max_end %lx\n", (unsigned long) x->begin,
428 (unsigned long) x->end, (unsigned long) x->max_end);
429 dbg_printf("search xl %lx xl_end %lx xl_max_end %lx\n", (unsigned long) xl->begin,
430 (unsigned long) xl->end, (unsigned long) xl->max_end);
431 if (!rcu_rbtree_is_nil(rbtree, xl)
432 && (rbtree->comp(xl->max_end, point) > 0)) {
433 dbg_printf("go left\n");
434 x = xl;
3d8a234b 435 } else if (rbtree->comp(x->begin, point) <= 0
66b64c35
MD
436 && rbtree->comp(point, x->end) < 0) {
437 dbg_printf("got it!\n");
438 break;
439 } else if (rbtree->comp(point, x->begin) > 0) {
440 dbg_printf("go right\n");
441 x = rcu_dereference(x->_right);
442 } else {
443 dbg_printf("not found!\n");
444 x = make_nil(rbtree);
445 }
446 }
447 if (rcu_rbtree_is_nil(rbtree, x))
448 dbg_printf("Reached bottom of tree.\n");
449
450 return x;
451}
452
453struct rcu_rbtree_node *rcu_rbtree_search_range(struct rcu_rbtree *rbtree,
454 struct rcu_rbtree_node *x,
455 void *begin, void *end)
456{
457 struct rcu_rbtree_node *node;
458
459 node = rcu_rbtree_search(rbtree, x, begin);
460 if (rcu_rbtree_is_nil(rbtree, node))
461 return node;
462 if (rbtree->comp(node->end, end) < 0)
463 return NULL; /* High is outside lookup range */
464 return node;
465}
466
467/*
468 * Search by exact range start value.
469 */
470struct rcu_rbtree_node *rcu_rbtree_search_begin_key(struct rcu_rbtree *rbtree,
dff86257
MD
471 struct rcu_rbtree_node *x,
472 void *k)
473{
474 x = rcu_dereference(x);
ac5f3963 475 int comp;
dff86257 476
3366b9c0 477 while (!rcu_rbtree_is_nil(rbtree, x) && (comp = rbtree->comp(k, x->begin)) != 0) {
9c161ee1 478 dbg_usleep(10);
ac5f3963 479 if (comp < 0)
dca45c9f 480 x = rcu_dereference(x->_left);
dff86257 481 else
dca45c9f 482 x = rcu_dereference(x->_right);
dff86257
MD
483 }
484 return x;
485}
486
230dd288
MD
487static
488struct rcu_rbtree_node *rcu_rbtree_min_dup_decay(struct rcu_rbtree *rbtree,
489 struct rcu_rbtree_node *x,
490 struct rcu_rbtree_node **zr)
491{
492 struct rcu_rbtree_node *xl;
493
494 x = rcu_dereference(x);
495
8ded5fe9 496 if (rcu_rbtree_is_nil(rbtree, x)) {
230dd288
MD
497 *zr = x;
498 return x;
499 } else
500 *zr = x = dup_decay_node(rbtree, x);
501
8ded5fe9 502 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left))) {
230dd288 503 x = dup_decay_node(rbtree, xl);
7ba89e62 504 set_parent(x, get_decay(get_parent(x)), get_pos(x));
dca45c9f 505 get_parent(x)->_left = get_decay(get_parent(x)->_left);
230dd288
MD
506 }
507 return x;
508}
509
510static
511struct rcu_rbtree_node *rcu_rbtree_min_update_decay(struct rcu_rbtree *rbtree,
512 struct rcu_rbtree_node *x)
513{
514 struct rcu_rbtree_node *xl;
515
516 x = rcu_dereference(x);
517
8ded5fe9 518 if (rcu_rbtree_is_nil(rbtree, x))
230dd288
MD
519 return x;
520 else {
dca45c9f
MD
521 set_parent(x->_right, get_decay(get_parent(x->_right)),
522 get_pos(x->_right));
523 set_parent(x->_left, get_decay(get_parent(x->_left)),
524 get_pos(x->_left));
230dd288
MD
525 }
526
8ded5fe9 527 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left))) {
230dd288 528 x = xl;
dca45c9f
MD
529 set_parent(x->_right, get_decay(get_parent(x->_right)),
530 get_pos(x->_right));
531 set_parent(x->_left, get_decay(get_parent(x->_left)),
532 get_pos(x->_left));
230dd288
MD
533 }
534 return x;
535}
536
dff86257
MD
537struct rcu_rbtree_node *rcu_rbtree_min(struct rcu_rbtree *rbtree,
538 struct rcu_rbtree_node *x)
539{
540 struct rcu_rbtree_node *xl;
541
542 x = rcu_dereference(x);
543
8ded5fe9 544 if (rcu_rbtree_is_nil(rbtree, x))
dff86257
MD
545 return x;
546
8ded5fe9 547 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left)))
dff86257
MD
548 x = xl;
549 return x;
550}
551
552struct rcu_rbtree_node *rcu_rbtree_max(struct rcu_rbtree *rbtree,
553 struct rcu_rbtree_node *x)
554{
555 struct rcu_rbtree_node *xr;
556
557 x = rcu_dereference(x);
558
8ded5fe9 559 if (rcu_rbtree_is_nil(rbtree, x))
dff86257
MD
560 return x;
561
8ded5fe9 562 while (!rcu_rbtree_is_nil(rbtree, xr = rcu_dereference(x->_right)))
dff86257
MD
563 x = xr;
564 return x;
565}
566
dff86257 567/*
7ba89e62
MD
568 * RCU read lock must be held across the next/prev calls to ensure validity of
569 * the returned node.
dff86257
MD
570 */
571struct rcu_rbtree_node *rcu_rbtree_next(struct rcu_rbtree *rbtree,
572 struct rcu_rbtree_node *x)
573{
269a9ef6 574 struct rcu_rbtree_node *xr, *y;
7ba89e62 575 unsigned int x_pos;
dff86257
MD
576
577 x = rcu_dereference(x);
578
8ded5fe9 579 if (!rcu_rbtree_is_nil(rbtree, xr = rcu_dereference(x->_right)))
dff86257 580 return rcu_rbtree_min(rbtree, xr);
7ba89e62 581 y = get_parent_and_pos(x, &x_pos);
8ded5fe9 582 while (!rcu_rbtree_is_nil(rbtree, y) && x_pos == IS_RIGHT) {
dff86257 583 x = y;
7ba89e62 584 y = get_parent_and_pos(y, &x_pos);
dff86257
MD
585 }
586 return y;
587}
588
589struct rcu_rbtree_node *rcu_rbtree_prev(struct rcu_rbtree *rbtree,
590 struct rcu_rbtree_node *x)
591{
269a9ef6 592 struct rcu_rbtree_node *xl, *y;
7ba89e62 593 unsigned int x_pos;
dff86257
MD
594
595 x = rcu_dereference(x);
596
8ded5fe9 597 if (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left)))
4aa30442 598 return rcu_rbtree_max(rbtree, xl);
7ba89e62 599 y = get_parent_and_pos(x, &x_pos);
8ded5fe9 600 while (!rcu_rbtree_is_nil(rbtree, y) && x_pos == IS_LEFT) {
dff86257 601 x = y;
7ba89e62 602 y = get_parent_and_pos(y, &x_pos);
dff86257
MD
603 }
604 return y;
605}
606
7bc64d1d
MD
607/*
608 * "node" needs to be non-visible by readers.
609 */
610static
611void populate_node_end(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node,
fcb4eea8 612 unsigned int copy_parents, struct rcu_rbtree_node *stop)
7bc64d1d
MD
613{
614 struct rcu_rbtree_node *prev = NULL, *orig_node = node, *top;
615
616 do {
617 void *max_end;
618
fcb4eea8 619 assert(node);
7bc64d1d 620 assert(!rcu_rbtree_is_nil(rbtree, node));
4459c487 621
66b64c35
MD
622 if (prev && copy_parents) {
623 node = dup_decay_node(rbtree, node);
624 if (get_pos(prev) == IS_RIGHT)
625 node->_right = prev;
626 else
627 node->_left = prev;
628 set_parent(prev, node, get_pos(prev));
629 }
630
fda7316a 631 max_end = calculate_node_max_end(rbtree, node);
66b64c35
MD
632 /*
633 * Compare the node max_end keys to make sure we replace
634 * references to a key belonging to a node we remove
635 * from the tree. Otherwise we would still be using this
636 * pointer as an invalid reference after garbage
637 * collection of the node and of its associated
638 * begin/end pointers.
639 */
640 if (max_end != node->max_end) {
7bc64d1d
MD
641 node->max_end = max_end;
642 } else {
7bc64d1d
MD
643 top = get_parent(node);
644 cmm_smp_wmb(); /* write into node before publish */
645 /* make new branch visible to readers */
646 if (rcu_rbtree_is_nil(rbtree, top))
647 _CMM_STORE_SHARED(rbtree->root, node);
648 if (get_pos(node) == IS_LEFT)
649 _CMM_STORE_SHARED(top->_left, node);
650 else
651 _CMM_STORE_SHARED(top->_right, node);
652 goto end;
653 }
fcb4eea8
MD
654
655 /* Check for propagation stop */
656 if (node == stop)
657 return;
658
7bc64d1d 659 prev = node;
fcb4eea8
MD
660 node = get_parent(node);
661 } while (!rcu_rbtree_is_nil(rbtree, node));
7bc64d1d
MD
662
663 top = node; /* nil */
664 cmm_smp_wmb(); /* write into node before publish */
665 /* make new branch visible to readers */
666 _CMM_STORE_SHARED(rbtree->root, prev);
667
668end:
fcb4eea8
MD
669 if (!copy_parents)
670 return;
7bc64d1d
MD
671 /* update children */
672 node = orig_node;
673 do {
674 assert(!rcu_rbtree_is_nil(rbtree, node));
675 set_parent(node->_left, get_decay(get_parent(node->_left)), IS_LEFT);
676 set_parent(node->_right, get_decay(get_parent(node->_right)), IS_RIGHT);
677 } while ((node = get_parent(node)) != top);
678}
679
dff86257
MD
680/*
681 * We have to ensure these assumptions are correct for prev/next
682 * traversal:
683 *
684 * with x being a right child, the assumption that:
dca45c9f 685 * get_parent(x)->_right == x
dff86257 686 * or if x is a left child, the assumption that:
dca45c9f 687 * get_parent(x)->_left == x
dff86257
MD
688 *
689 * This explains why we have to allocate a vc copy of the node for left_rotate,
690 * right_rotate and transplant operations.
691 *
692 * We always ensure that the right/left child and correct parent is set in the
693 * node copies *before* we reparent the children and make the upper-level point
694 * to the copy.
695 */
696
697/* RCU: copy x and y, atomically point to new versions. GC old. */
698/* Should be eventually followed by a cmm_smp_wmc() */
dff86257 699
dbe4ae98
MD
700#ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
701
dff86257 702static
269a9ef6
MD
703void left_rotate(struct rcu_rbtree *rbtree,
704 struct rcu_rbtree_node *x)
dff86257 705{
a84e8c8e 706 struct rcu_rbtree_node *y, *y_left;
dff86257 707
66b64c35
MD
708 dbg_printf("left rotate %lx\n", (unsigned long) x->begin);
709
dca45c9f
MD
710 y = x->_right;
711 y_left = y->_left;
269a9ef6
MD
712
713 /* Now operate on new copy, decay old versions */
dbe4ae98
MD
714 x = dup_decay_node(rbtree, x);
715 y = dup_decay_node(rbtree, y);
716 y_left = dup_decay_node(rbtree, y_left);
269a9ef6 717
66b64c35
MD
718 check_max_end(rbtree, get_parent(x));
719 check_max_end(rbtree, x);
720 check_max_end(rbtree, y);
721
676dd8b6 722 /* Internal node modifications */
7ba89e62
MD
723 set_parent(y, get_parent(x), get_pos(x));
724 set_parent(x, y, IS_LEFT);
a84e8c8e
MD
725 set_left(rbtree, y, x);
726 set_right(rbtree, x, y_left);
dca45c9f 727
8ded5fe9 728 if (!rcu_rbtree_is_nil(rbtree, y_left))
7ba89e62 729 set_parent(y_left, x, IS_RIGHT);
676dd8b6 730
fda7316a
MD
731 /*
732 * We only changed the relative position of x and y wrt their
733 * children, and reparented y (but are keeping the same nodes in
734 * place, so its parent does not need to have end value
735 * recalculated).
736 */
737 x->max_end = calculate_node_max_end(rbtree, x);
738 y->max_end = calculate_node_max_end(rbtree, y);
739
676dd8b6
MD
740 cmm_smp_wmb(); /* write into node before publish */
741
742 /* External references update (visible by readers) */
a84e8c8e
MD
743 if (rcu_rbtree_is_nil(rbtree, get_parent(y)))
744 _CMM_STORE_SHARED(rbtree->root, y);
745 else if (get_pos(y) == IS_LEFT)
746 _CMM_STORE_SHARED(get_parent(y)->_left, y);
676dd8b6 747 else
a84e8c8e 748 _CMM_STORE_SHARED(get_parent(y)->_right, y);
676dd8b6 749
dbe4ae98 750 /* Point children to new copy (parent only used by updates/next/prev) */
dca45c9f
MD
751 set_parent(x->_left, get_decay(get_parent(x->_left)),
752 get_pos(x->_left));
753 set_parent(y->_right, get_decay(get_parent(y->_right)),
754 get_pos(y->_right));
8ded5fe9 755 if (!rcu_rbtree_is_nil(rbtree, y_left)) {
dca45c9f
MD
756 set_parent(y_left->_right,
757 get_decay(get_parent(y_left->_right)),
758 get_pos(y_left->_right));
759 set_parent(y_left->_left,
760 get_decay(get_parent(y_left->_left)),
761 get_pos(y_left->_left));
dbe4ae98 762 }
269a9ef6
MD
763
764 /* Sanity checks */
dca45c9f
MD
765 assert(y == rbtree->root || get_parent(y)->_left == y
766 || get_parent(y)->_right == y);
767 assert(x == rbtree->root || get_parent(x)->_left == x
768 || get_parent(x)->_right == x);
8ded5fe9
MD
769 assert(rcu_rbtree_is_nil(rbtree, x->_right) || get_parent(x->_right) == x);
770 assert(rcu_rbtree_is_nil(rbtree, x->_left) || get_parent(x->_left) == x);
771 assert(rcu_rbtree_is_nil(rbtree, y->_right) || get_parent(y->_right) == y);
772 assert(rcu_rbtree_is_nil(rbtree, y->_left) || get_parent(y->_left) == y);
269a9ef6
MD
773 assert(!is_decay(rbtree->root));
774 assert(!is_decay(x));
775 assert(!is_decay(y));
dca45c9f
MD
776 assert(!is_decay(x->_right));
777 assert(!is_decay(x->_left));
778 assert(!is_decay(y->_right));
779 assert(!is_decay(y->_left));
66b64c35
MD
780 check_max_end(rbtree, get_parent(y));
781 check_max_end(rbtree, x);
782 check_max_end(rbtree, y);
dff86257
MD
783}
784
dbe4ae98
MD
785#else
786
787/* non-rcu version */
788static
789void left_rotate(struct rcu_rbtree *rbtree,
790 struct rcu_rbtree_node *x)
791{
792 struct rcu_rbtree_node *y;
793
230dd288 794 lock_test_mutex();
dca45c9f
MD
795 y = x->_right;
796 x->_right = y->_left;
8ded5fe9 797 if (!rcu_rbtree_is_nil(rbtree, y->_left))
dca45c9f 798 set_parent(y->_left, x, IS_RIGHT);
7ba89e62 799 set_parent(y, get_parent(x), get_pos(x));
8ded5fe9 800 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
dbe4ae98 801 rbtree->root = y;
dca45c9f
MD
802 else if (x == get_parent(x)->_left) {
803 get_parent(x)->_left = y;
dbe4ae98 804 } else {
dca45c9f 805 get_parent(x)->_right = y;
dbe4ae98 806 }
dca45c9f 807 y->_left = x;
7ba89e62 808 set_parent(x, y, IS_LEFT);
1444707c
MD
809
810 /*
811 * We only changed the relative position of x and y wrt their
812 * children, and reparented y (but are keeping the same nodes in
813 * place, so its parent does not need to have end value
814 * recalculated).
815 */
816 x->max_end = calculate_node_max_end(rbtree, x);
817 y->max_end = calculate_node_max_end(rbtree, y);
818
230dd288 819 unlock_test_mutex();
dbe4ae98
MD
820}
821
822#endif
823
824#ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
dff86257 825static
269a9ef6
MD
826void right_rotate(struct rcu_rbtree *rbtree,
827 struct rcu_rbtree_node *x)
dff86257 828{
a84e8c8e 829 struct rcu_rbtree_node *y, *y_right;
dff86257 830
66b64c35
MD
831 dbg_printf("right rotate %lx\n", (unsigned long) x->begin);
832
dca45c9f
MD
833 y = x->_left;
834 y_right = y->_right;
269a9ef6
MD
835
836 /* Now operate on new copy, decay old versions */
dbe4ae98
MD
837 x = dup_decay_node(rbtree, x);
838 y = dup_decay_node(rbtree, y);
839 y_right = dup_decay_node(rbtree, y_right);
269a9ef6 840
66b64c35
MD
841 check_max_end(rbtree, get_parent(x));
842 check_max_end(rbtree, x);
843 check_max_end(rbtree, y);
844
676dd8b6 845 /* Internal node modifications */
7ba89e62
MD
846 set_parent(y, get_parent(x), get_pos(x));
847 set_parent(x, y, IS_RIGHT);
a84e8c8e
MD
848 set_right(rbtree, y, x);
849 set_left(rbtree, x, y_right);
dca45c9f 850
8ded5fe9 851 if (!rcu_rbtree_is_nil(rbtree, y_right))
7ba89e62 852 set_parent(y_right, x, IS_LEFT);
676dd8b6 853
fda7316a
MD
854 /*
855 * We only changed the relative position of x and y wrt their
856 * children, and reparented y (but are keeping the same nodes in
857 * place, so its parent does not need to have end value
858 * recalculated).
859 */
860 x->max_end = calculate_node_max_end(rbtree, x);
861 y->max_end = calculate_node_max_end(rbtree, y);
862
676dd8b6
MD
863 cmm_smp_wmb(); /* write into node before publish */
864
865 /* External references update (visible by readers) */
a84e8c8e
MD
866 if (rcu_rbtree_is_nil(rbtree, get_parent(y)))
867 _CMM_STORE_SHARED(rbtree->root, y);
868 else if (get_pos(y) == IS_RIGHT)
869 _CMM_STORE_SHARED(get_parent(y)->_right, y);
676dd8b6 870 else
a84e8c8e 871 _CMM_STORE_SHARED(get_parent(y)->_left, y);
676dd8b6 872
dbe4ae98 873 /* Point children to new copy (parent only used by updates/next/prev) */
dca45c9f
MD
874 set_parent(x->_right, get_decay(get_parent(x->_right)),
875 get_pos(x->_right));
876 set_parent(y->_left, get_decay(get_parent(y->_left)),
877 get_pos(y->_left));
8ded5fe9 878 if (!rcu_rbtree_is_nil(rbtree, y_right)) {
dca45c9f
MD
879 set_parent(y_right->_left,
880 get_decay(get_parent(y_right->_left)),
881 get_pos(y_right->_left));
882 set_parent(y_right->_right,
883 get_decay(get_parent(y_right->_right)),
884 get_pos(y_right->_right));
dbe4ae98 885 }
269a9ef6
MD
886
887 /* Sanity checks */
dca45c9f
MD
888 assert(y == rbtree->root || get_parent(y)->_right == y
889 || get_parent(y)->_left == y);
890 assert(x == rbtree->root || get_parent(x)->_right == x
891 || get_parent(x)->_left == x);
8ded5fe9
MD
892 assert(rcu_rbtree_is_nil(rbtree, x->_left) || get_parent(x->_left) == x);
893 assert(rcu_rbtree_is_nil(rbtree, x->_right) || get_parent(x->_right) == x);
894 assert(rcu_rbtree_is_nil(rbtree, y->_left) || get_parent(y->_left) == y);
895 assert(rcu_rbtree_is_nil(rbtree, y->_right) || get_parent(y->_right) == y);
269a9ef6
MD
896 assert(!is_decay(rbtree->root));
897 assert(!is_decay(x));
898 assert(!is_decay(y));
dca45c9f
MD
899 assert(!is_decay(x->_left));
900 assert(!is_decay(x->_right));
901 assert(!is_decay(y->_left));
902 assert(!is_decay(y->_right));
66b64c35
MD
903 check_max_end(rbtree, x);
904 check_max_end(rbtree, y);
905 check_max_end(rbtree, get_parent(y));
dff86257
MD
906}
907
6daf6090
MD
908#else
909
dbe4ae98 910/* non-rcu version */
6daf6090
MD
911static
912void right_rotate(struct rcu_rbtree *rbtree,
913 struct rcu_rbtree_node *x)
914{
915 struct rcu_rbtree_node *y;
916
230dd288 917 lock_test_mutex();
dca45c9f
MD
918 y = x->_left;
919 x->_left = y->_right;
8ded5fe9 920 if (!rcu_rbtree_is_nil(rbtree, y->_right))
dca45c9f 921 set_parent(y->_right, x, IS_LEFT);
7ba89e62 922 set_parent(y, get_parent(x), get_pos(x));
8ded5fe9 923 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
6daf6090 924 rbtree->root = y;
dca45c9f
MD
925 else if (x == get_parent(x)->_right) {
926 get_parent(x)->_right = y;
6daf6090 927 } else {
dca45c9f 928 get_parent(x)->_left = y;
6daf6090 929 }
dca45c9f 930 y->_right = x;
7ba89e62 931 set_parent(x, y, IS_RIGHT);
1444707c
MD
932
933 /*
934 * We only changed the relative position of x and y wrt their
935 * children, and reparented y (but are keeping the same nodes in
936 * place, so its parent does not need to have end value
937 * recalculated).
938 */
939 x->max_end = calculate_node_max_end(rbtree, x);
940 y->max_end = calculate_node_max_end(rbtree, y);
941
230dd288 942 unlock_test_mutex();
6daf6090
MD
943}
944
945#endif
946
dff86257
MD
947static void rcu_rbtree_insert_fixup(struct rcu_rbtree *rbtree,
948 struct rcu_rbtree_node *z)
949{
950 struct rcu_rbtree_node *y;
951
3366b9c0 952 dbg_printf("insert fixup %p\n", z->begin);
269a9ef6 953 assert(!is_decay(rbtree->root));
dff86257 954
7ba89e62 955 while (get_parent(z)->color == COLOR_RED) {
dca45c9f
MD
956 if (get_parent(z) == get_parent(get_parent(z))->_left) {
957 y = get_parent(get_parent(z))->_right;
dff86257 958 if (y->color == COLOR_RED) {
7ba89e62 959 get_parent(z)->color = COLOR_BLACK;
dff86257 960 y->color = COLOR_BLACK;
7ba89e62
MD
961 get_parent(get_parent(z))->color = COLOR_RED;
962 z = get_parent(get_parent(z));
dff86257 963 } else {
dca45c9f 964 if (z == get_parent(z)->_right) {
7ba89e62 965 z = get_parent(z);
dff86257 966 left_rotate(rbtree, z);
269a9ef6
MD
967 z = get_decay(z);
968 assert(!is_decay(rbtree->root));
dff86257 969 }
7ba89e62
MD
970 get_parent(z)->color = COLOR_BLACK;
971 get_parent(get_parent(z))->color = COLOR_RED;
269a9ef6 972 assert(!is_decay(z));
7ba89e62
MD
973 assert(!is_decay(get_parent(z)));
974 assert(!is_decay(get_parent(get_parent(z))));
975 right_rotate(rbtree, get_parent(get_parent(z)));
269a9ef6
MD
976 assert(!is_decay(z));
977 assert(!is_decay(rbtree->root));
dff86257
MD
978 }
979 } else {
dca45c9f 980 y = get_parent(get_parent(z))->_left;
dff86257 981 if (y->color == COLOR_RED) {
7ba89e62 982 get_parent(z)->color = COLOR_BLACK;
dff86257 983 y->color = COLOR_BLACK;
7ba89e62
MD
984 get_parent(get_parent(z))->color = COLOR_RED;
985 z = get_parent(get_parent(z));
dff86257 986 } else {
dca45c9f 987 if (z == get_parent(z)->_left) {
7ba89e62 988 z = get_parent(z);
dff86257 989 right_rotate(rbtree, z);
269a9ef6
MD
990 z = get_decay(z);
991 assert(!is_decay(rbtree->root));
dff86257 992 }
7ba89e62
MD
993 get_parent(z)->color = COLOR_BLACK;
994 get_parent(get_parent(z))->color = COLOR_RED;
995 left_rotate(rbtree, get_parent(get_parent(z)));
269a9ef6
MD
996 assert(!is_decay(z));
997 assert(!is_decay(rbtree->root));
dff86257
MD
998 }
999 }
1000 }
1001 rbtree->root->color = COLOR_BLACK;
1002}
1003
1004/*
1005 * rcu_rbtree_insert - Insert a node in the RCU rbtree
1006 *
1007 * Returns 0 on success, or < 0 on error.
1008 */
1009int rcu_rbtree_insert(struct rcu_rbtree *rbtree,
3c672595 1010 void *begin, void *end)
dff86257 1011{
3c672595
MD
1012 struct rcu_rbtree_node *x, *y, *z;
1013
8f354bc4
MD
1014 z = _rcu_rbtree_alloc_node(rbtree);
1015 if (!z)
1016 return -ENOMEM;
3c672595
MD
1017 z->begin = begin;
1018 z->end = end;
dff86257 1019
3366b9c0 1020 dbg_printf("insert %p\n", z->begin);
269a9ef6 1021 assert(!is_decay(rbtree->root));
dff86257
MD
1022
1023 y = make_nil(rbtree);
dff86257 1024 x = rbtree->root;
8ded5fe9 1025 while (!rcu_rbtree_is_nil(rbtree, x)) {
dff86257 1026 y = x;
3366b9c0 1027 if (rbtree->comp(z->begin, x->begin) < 0)
dca45c9f 1028 x = x->_left;
dff86257 1029 else
dca45c9f 1030 x = x->_right;
dff86257
MD
1031 }
1032
dca45c9f
MD
1033 z->_left = make_nil(rbtree);
1034 z->_right = make_nil(rbtree);
dff86257 1035 z->color = COLOR_RED;
269a9ef6 1036 z->decay_next = NULL;
55b5e812 1037 z->max_end = z->end;
3c672595 1038 z->rbtree = rbtree;
dff86257 1039
8ded5fe9 1040 if (rcu_rbtree_is_nil(rbtree, y)) {
7bc64d1d 1041 set_parent(z, y, IS_RIGHT); /* pos arbitrary for root node */
0bd215cc
MD
1042 /*
1043 * Order stores to z (children/parents) before stores
1044 * that will make it visible to the rest of the tree.
1045 */
1046 cmm_smp_wmb();
dff86257 1047 _CMM_STORE_SHARED(rbtree->root, z);
3366b9c0 1048 } else if (rbtree->comp(z->begin, y->begin) < 0) {
7bc64d1d
MD
1049 y = dup_decay_node(rbtree, y);
1050 set_parent(z, y, IS_LEFT);
1051 if (get_pos(z) == IS_LEFT)
a84e8c8e 1052 _CMM_STORE_SHARED(y->_left, z);
dca45c9f 1053 else
a84e8c8e 1054 _CMM_STORE_SHARED(y->_right, z);
fcb4eea8 1055 populate_node_end(rbtree, y, 1, NULL);
dca45c9f 1056 } else {
7bc64d1d
MD
1057 y = dup_decay_node(rbtree, y);
1058 set_parent(z, y, IS_RIGHT);
1059 if (get_pos(z) == IS_LEFT)
a84e8c8e 1060 _CMM_STORE_SHARED(y->_left, z);
dca45c9f 1061 else
a84e8c8e 1062 _CMM_STORE_SHARED(y->_right, z);
fcb4eea8 1063 populate_node_end(rbtree, y, 1, NULL);
dca45c9f 1064 }
dff86257
MD
1065 rcu_rbtree_insert_fixup(rbtree, z);
1066 /*
1067 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
1068 */
1069 cmm_smp_wmc();
1070 show_tree(rbtree);
66b64c35
MD
1071 check_max_end(rbtree, z);
1072 check_max_end(rbtree, y);
dff86257
MD
1073
1074 return 0;
1075}
1076
1077/*
1078 * Transplant v into u position.
dff86257 1079 */
6daf6090
MD
1080
1081#ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
1082
269a9ef6
MD
1083static
1084void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
1085 struct rcu_rbtree_node *u,
dca45c9f 1086 struct rcu_rbtree_node *v,
fcb4eea8
MD
1087 unsigned int copy_parents,
1088 struct rcu_rbtree_node *stop)
dff86257 1089{
3366b9c0 1090 dbg_printf("transplant %p\n", v->begin);
dff86257 1091
8ded5fe9 1092 if (!rcu_rbtree_is_nil(rbtree, v))
dbe4ae98 1093 v = dup_decay_node(rbtree, v);
c479601c 1094
8ded5fe9 1095 if (rcu_rbtree_is_nil(rbtree, get_parent(u))) {
7ba89e62
MD
1096 /* pos is arbitrary for root node */
1097 set_parent(v, get_parent(u), IS_RIGHT);
c479601c
MD
1098 cmm_smp_wmb(); /* write into node before publish */
1099 _CMM_STORE_SHARED(rbtree->root, v);
dff86257 1100 } else {
fcb4eea8
MD
1101 struct rcu_rbtree_node *vp;
1102
1103 vp = get_parent(u);
1104 if (copy_parents)
1105 vp = dup_decay_node(rbtree, vp);
1106 set_parent(v, vp, get_pos(u));
1107 if (get_pos(v) == IS_LEFT)
1108 _CMM_STORE_SHARED(vp->_left, v);
806967f3 1109 else
fcb4eea8
MD
1110 _CMM_STORE_SHARED(vp->_right, v);
1111 populate_node_end(rbtree, vp, copy_parents, stop);
66b64c35 1112 check_max_end(rbtree, vp);
c479601c 1113 }
806967f3 1114
dbe4ae98 1115 /* Point children to new copy (parent only used by updates/next/prev) */
8ded5fe9 1116 if (!rcu_rbtree_is_nil(rbtree, v)) {
dca45c9f
MD
1117 set_parent(v->_right, get_decay(get_parent(v->_right)),
1118 get_pos(v->_right));
1119 set_parent(v->_left, get_decay(get_parent(v->_left)),
1120 get_pos(v->_left));
dff86257 1121 }
269a9ef6 1122 assert(!is_decay(rbtree->root));
66b64c35 1123 check_max_end(rbtree, v);
dff86257
MD
1124}
1125
6daf6090
MD
1126#else
1127
1128/* Non-RCU version */
1129static
1130void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
1131 struct rcu_rbtree_node *u,
dca45c9f 1132 struct rcu_rbtree_node *v,
fcb4eea8
MD
1133 unsigned int copy_parents,
1134 struct rcu_rbtree_node *stop)
6daf6090 1135{
3366b9c0 1136 dbg_printf("transplant %p\n", v->begin);
6daf6090 1137
230dd288 1138 lock_test_mutex();
1444707c 1139 if (rcu_rbtree_is_nil(rbtree, get_parent(u))) {
6daf6090 1140 rbtree->root = v;
1444707c
MD
1141 } else {
1142 if (u == get_parent(u)->_left)
1143 get_parent(u)->_left = v;
1144 else
1145 get_parent(u)->_right = v;
1146 populate_node_end(rbtree, get_parent(u), copy_parents, stop);
1147 }
7ba89e62 1148 set_parent(v, get_parent(u), get_pos(u));
230dd288 1149 unlock_test_mutex();
6daf6090
MD
1150}
1151
1152#endif
1153
dff86257
MD
1154static void rcu_rbtree_remove_fixup(struct rcu_rbtree *rbtree,
1155 struct rcu_rbtree_node *x)
1156{
3366b9c0 1157 dbg_printf("remove fixup %p\n", x->begin);
dff86257
MD
1158
1159 while (x != rbtree->root && x->color == COLOR_BLACK) {
7ba89e62 1160 assert(!is_decay(get_parent(x)));
dca45c9f
MD
1161 assert(!is_decay(get_parent(x)->_left));
1162 if (x == get_parent(x)->_left) {
269a9ef6 1163 struct rcu_rbtree_node *w;
dff86257 1164
dca45c9f 1165 w = get_parent(x)->_right;
dff86257
MD
1166
1167 if (w->color == COLOR_RED) {
269a9ef6 1168 w->color = COLOR_BLACK;
7ba89e62
MD
1169 get_parent(x)->color = COLOR_RED;
1170 left_rotate(rbtree, get_parent(x));
269a9ef6
MD
1171 x = get_decay(x);
1172 assert(!is_decay(rbtree->root));
dca45c9f 1173 w = get_parent(x)->_right;
dff86257 1174 }
dca45c9f
MD
1175 if (w->_left->color == COLOR_BLACK
1176 && w->_right->color == COLOR_BLACK) {
dff86257 1177 w->color = COLOR_RED;
7ba89e62 1178 x = get_parent(x);
c479601c
MD
1179 assert(!is_decay(rbtree->root));
1180 assert(!is_decay(x));
dff86257 1181 } else {
dca45c9f
MD
1182 if (w->_right->color == COLOR_BLACK) {
1183 w->_left->color = COLOR_BLACK;
dff86257
MD
1184 w->color = COLOR_RED;
1185 right_rotate(rbtree, w);
c479601c 1186 assert(!is_decay(rbtree->root));
269a9ef6 1187 x = get_decay(x);
dca45c9f 1188 w = get_parent(x)->_right;
dff86257 1189 }
7ba89e62
MD
1190 w->color = get_parent(x)->color;
1191 get_parent(x)->color = COLOR_BLACK;
dca45c9f 1192 w->_right->color = COLOR_BLACK;
7ba89e62 1193 left_rotate(rbtree, get_parent(x));
269a9ef6 1194 assert(!is_decay(rbtree->root));
dff86257
MD
1195 x = rbtree->root;
1196 }
1197 } else {
269a9ef6 1198 struct rcu_rbtree_node *w;
dff86257 1199
dca45c9f 1200 w = get_parent(x)->_left;
dff86257
MD
1201
1202 if (w->color == COLOR_RED) {
269a9ef6 1203 w->color = COLOR_BLACK;
7ba89e62
MD
1204 get_parent(x)->color = COLOR_RED;
1205 right_rotate(rbtree, get_parent(x));
c479601c 1206 assert(!is_decay(rbtree->root));
269a9ef6 1207 x = get_decay(x);
dca45c9f 1208 w = get_parent(x)->_left;
dff86257 1209 }
dca45c9f
MD
1210 if (w->_right->color == COLOR_BLACK
1211 && w->_left->color == COLOR_BLACK) {
dff86257 1212 w->color = COLOR_RED;
7ba89e62 1213 x = get_parent(x);
c479601c
MD
1214 assert(!is_decay(rbtree->root));
1215 assert(!is_decay(x));
dff86257 1216 } else {
dca45c9f
MD
1217 if (w->_left->color == COLOR_BLACK) {
1218 w->_right->color = COLOR_BLACK;
dff86257
MD
1219 w->color = COLOR_RED;
1220 left_rotate(rbtree, w);
269a9ef6
MD
1221 assert(!is_decay(rbtree->root));
1222 x = get_decay(x);
dca45c9f 1223 w = get_parent(x)->_left;
dff86257 1224 }
7ba89e62
MD
1225 w->color = get_parent(x)->color;
1226 get_parent(x)->color = COLOR_BLACK;
dca45c9f 1227 w->_left->color = COLOR_BLACK;
7ba89e62 1228 right_rotate(rbtree, get_parent(x));
c479601c 1229 assert(!is_decay(rbtree->root));
dff86257
MD
1230 x = rbtree->root;
1231 }
1232 }
1233 }
1234 x->color = COLOR_BLACK;
1235}
1236
1237/*
269a9ef6
MD
1238 * Delete z. All non-copied children left/right positions are unchanged.
1239 */
1240static
1241void rcu_rbtree_remove_nonil(struct rcu_rbtree *rbtree,
1242 struct rcu_rbtree_node *z,
1243 struct rcu_rbtree_node *y)
dff86257 1244{
a84e8c8e 1245 struct rcu_rbtree_node *x;
dff86257 1246
3366b9c0 1247 dbg_printf("remove nonil %p\n", z->begin);
dff86257
MD
1248 show_tree(rbtree);
1249
c479601c
MD
1250 assert(!is_decay(z));
1251 assert(!is_decay(y));
dca45c9f 1252 assert(!is_decay(y->_right));
7ba89e62 1253 assert(!is_decay(get_parent(y)));
dca45c9f 1254 x = y->_right;
c479601c 1255 assert(!is_decay(x));
7ba89e62 1256 if (get_parent(y) == z) {
230dd288 1257 y = dup_decay_node(rbtree, y);
7ba89e62 1258 set_parent(x, y, get_pos(x)); /* parent for nil */
66b64c35 1259 /* y is z's right node */
a84e8c8e 1260 set_left(rbtree, y, z->_left);
66b64c35 1261 y->max_end = calculate_node_max_end(rbtree, y);
fcb4eea8 1262 rcu_rbtree_transplant(rbtree, z, y, 1, NULL);
230dd288
MD
1263 } else {
1264 struct rcu_rbtree_node *oy_right, *z_right;
1265
1266 /*
1267 * Need to make sure y is always visible by readers.
1268 */
dca45c9f 1269 y = rcu_rbtree_min_dup_decay(rbtree, z->_right, &z_right);
269a9ef6
MD
1270 assert(!is_decay(y));
1271 assert(!is_decay(z));
dca45c9f
MD
1272 oy_right = y->_right;
1273
1274 /*
3366b9c0 1275 * The max child begin of z_right does not change, because
dca45c9f
MD
1276 * we're only changing its left children.
1277 */
1278 y->_right = z_right;
1279 set_parent(y->_right, y, IS_RIGHT);
dca45c9f
MD
1280 assert(!is_decay(z->_left));
1281 y->_left = z->_left;
230dd288 1282 assert(!is_decay(oy_right));
dca45c9f
MD
1283 /*
1284 * Transplant of oy_right to old y's location will only
fcb4eea8 1285 * trigger a "end" value update of the already copied branch
dca45c9f
MD
1286 * (which is not visible yet). We are transplanting
1287 * oy_right as a left child of old y's parent, so the
1288 * min values update propagated upward necessarily stops
1289 * at z_right.
1290 */
fcb4eea8 1291 rcu_rbtree_transplant(rbtree, y, oy_right, 0, y);
66b64c35 1292 y->max_end = calculate_node_max_end(rbtree, y);
fcb4eea8 1293 rcu_rbtree_transplant(rbtree, z, y, 1, NULL);
230dd288 1294 /* Update children */
dca45c9f 1295 (void) rcu_rbtree_min_update_decay(rbtree, y->_right);
dff86257 1296 }
c479601c 1297 y = get_decay(y);
269a9ef6 1298 assert(!is_decay(z));
dca45c9f 1299 assert(!is_decay(z->_left));
dff86257 1300 y->color = z->color;
dca45c9f
MD
1301 set_parent(y->_left, y, IS_LEFT);
1302 set_parent(y->_right, get_decay(get_parent(y->_right)), IS_RIGHT);
1303 assert(!is_decay(y->_left));
1304 assert(!is_decay(y->_right));
dff86257
MD
1305}
1306
1307int rcu_rbtree_remove(struct rcu_rbtree *rbtree,
1308 struct rcu_rbtree_node *z)
1309{
1310 struct rcu_rbtree_node *x, *y;
1311 unsigned int y_original_color;
1312
269a9ef6 1313 assert(!is_decay(rbtree->root));
3366b9c0 1314 dbg_printf("remove %p\n", z->begin);
dff86257
MD
1315 show_tree(rbtree);
1316
c479601c 1317 assert(!is_decay(z));
dff86257
MD
1318 y = z;
1319 y_original_color = y->color;
1320
8ded5fe9 1321 if (rcu_rbtree_is_nil(rbtree, z->_left)) {
fcb4eea8 1322 rcu_rbtree_transplant(rbtree, z, z->_right, 1, NULL);
269a9ef6 1323 assert(!is_decay(z));
dca45c9f 1324 x = get_decay(z->_right);
dff86257 1325 show_tree(rbtree);
8ded5fe9 1326 } else if (rcu_rbtree_is_nil(rbtree, z->_right)) {
fcb4eea8 1327 rcu_rbtree_transplant(rbtree, z, z->_left, 1, NULL);
269a9ef6 1328 assert(!is_decay(z));
dca45c9f 1329 x = get_decay(z->_left);
dff86257
MD
1330 show_tree(rbtree);
1331 } else {
dca45c9f 1332 y = rcu_rbtree_min(rbtree, z->_right);
c479601c 1333 assert(!is_decay(y));
dff86257 1334 y_original_color = y->color;
dca45c9f 1335 x = y->_right;
269a9ef6 1336 rcu_rbtree_remove_nonil(rbtree, z, y);
6daf6090 1337 x = get_decay(x);
dff86257
MD
1338 show_tree(rbtree);
1339 }
1340 if (y_original_color == COLOR_BLACK)
1341 rcu_rbtree_remove_fixup(rbtree, x);
1342 show_tree(rbtree);
66b64c35
MD
1343 check_max_end(rbtree, x);
1344 check_max_end(rbtree, get_decay(y));
dff86257
MD
1345 /*
1346 * Commit all _CMM_STORE_SHARED().
1347 */
1348 cmm_smp_wmc();
c2ceb27c 1349#ifdef RBTREE_RCU_SUPPORT
1cdd423d 1350 rbtree->call_rcu(&z->head, _rcu_rbtree_free_node);
c2ceb27c
MD
1351#else
1352 _rcu_rbtree_free_node(&z->head);
1353#endif
dff86257
MD
1354
1355 return 0;
1356}
This page took 0.086739 seconds and 4 git commands to generate.