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