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