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