rbtree: Add end recalculation for transplant
[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>
dff86257
MD
38
39#include <urcu/rcurbtree.h>
40#include <urcu-pointer.h>
c479601c 41#include <urcu-call-rcu.h>
dca45c9f 42#include <urcu/compiler.h>
dff86257 43
dff86257
MD
44#ifdef DEBUG
45#define dbg_printf(args...) printf(args)
9c161ee1 46#define dbg_usleep(usecs) usleep(usecs)
dff86257
MD
47#else
48#define dbg_printf(args...)
9c161ee1 49#define dbg_usleep(usecs)
dff86257
MD
50#endif
51
6daf6090
MD
52/*
53 * Undefine this to enable the non-RCU rotate and transplant functions
54 * (for debugging).
55 */
dbe4ae98
MD
56#define RBTREE_RCU_SUPPORT_ROTATE_LEFT
57#define RBTREE_RCU_SUPPORT_ROTATE_RIGHT
6daf6090
MD
58#define RBTREE_RCU_SUPPORT_TRANSPLANT
59
230dd288
MD
60#ifdef EXTRA_DEBUG
61static pthread_mutex_t test_mutex = PTHREAD_MUTEX_INITIALIZER;
62static pthread_mutex_t outer_mutex = PTHREAD_MUTEX_INITIALIZER;
63
64static
65void lock_outer_mutex(void)
66{
67 pthread_mutex_lock(&outer_mutex);
68}
69
70static
71void unlock_outer_mutex(void)
72{
73 pthread_mutex_unlock(&outer_mutex);
74}
75
76static
77void lock_test_mutex(void)
78{
79 pthread_mutex_lock(&test_mutex);
80}
81
82static
83void unlock_test_mutex(void)
84{
85 pthread_mutex_unlock(&test_mutex);
86}
87#endif
88
7ba89e62
MD
89static
90void set_parent(struct rcu_rbtree_node *node,
91 struct rcu_rbtree_node *parent,
92 unsigned int pos)
93{
9606ca85 94 _CMM_STORE_SHARED(node->parent, ((unsigned long) parent) | pos);
7ba89e62
MD
95}
96
97static
98struct rcu_rbtree_node *get_parent(struct rcu_rbtree_node *node)
99{
100 return (struct rcu_rbtree_node *) (node->parent & ~1UL);
101}
102
103static
104unsigned int get_pos(struct rcu_rbtree_node *node)
105{
106 return (unsigned int) (node->parent & 1UL);
107}
108
109static
110struct rcu_rbtree_node *get_parent_and_pos(struct rcu_rbtree_node *node,
111 unsigned int *pos)
112{
113 unsigned long parent_pos = rcu_dereference(node->parent);
114
115 *pos = (unsigned int) (parent_pos & 1UL);
116 return (struct rcu_rbtree_node *) (parent_pos & ~1UL);
117}
118
269a9ef6
MD
119static
120void set_decay(struct rcu_rbtree_node *x, struct rcu_rbtree_node *xc)
121{
122 x->decay_next = xc;
123}
124
125static
126struct rcu_rbtree_node *get_decay(struct rcu_rbtree_node *x)
127{
dbe4ae98
MD
128 if (!x)
129 return NULL;
269a9ef6
MD
130 while (x->decay_next)
131 x = x->decay_next;
132 return x;
133}
134
135static
136struct rcu_rbtree_node *is_decay(struct rcu_rbtree_node *x)
137{
138 return x->decay_next;
139}
140
141static
142struct rcu_rbtree_node *dup_decay_node(struct rcu_rbtree *rbtree,
143 struct rcu_rbtree_node *x)
144{
145 struct rcu_rbtree_node *xc;
146
8ded5fe9 147 if (rcu_rbtree_is_nil(rbtree, x))
269a9ef6
MD
148 return x;
149
150 xc = rbtree->rballoc();
151 memcpy(xc, x, sizeof(struct rcu_rbtree_node));
152 xc->decay_next = NULL;
153 set_decay(x, xc);
c479601c 154 call_rcu(&x->head, rbtree->rbfree);
269a9ef6
MD
155 return xc;
156}
157
dca45c9f
MD
158/*
159 * Info for range lookups:
160 * Range lookup information is only valid when used when searching for
161 * ranges. It should never be used in next/prev traversal because the
162 * pointers to parents are not in sync with the parent vision of the
163 * children range.
164 */
165static
a84e8c8e
MD
166void set_left(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node,
167 struct rcu_rbtree_node *left)
dca45c9f 168{
dca45c9f 169 node->_left = left;
dca45c9f
MD
170}
171
172static
a84e8c8e
MD
173void set_right(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node,
174 struct rcu_rbtree_node *right)
dca45c9f 175{
dca45c9f 176 node->_right = right;
dca45c9f
MD
177}
178
dff86257
MD
179/*
180 * TODO
181 * Deal with memory allocation errors.
182 * Can be ensured by reserving a pool of memory entries before doing the
183 * insertion, which will have to be function of number of
184 * transplantations/rotations required for the operation.
185 */
186
5d2c985d 187#ifdef DEBUG
dff86257
MD
188static
189void show_tree(struct rcu_rbtree *rbtree)
190{
191 struct rcu_rbtree_node *node;
192
193 node = rcu_rbtree_min(rbtree, rbtree->root);
8ded5fe9 194 while (!rcu_rbtree_is_nil(rbtree, node)) {
269a9ef6 195 assert(!is_decay(node));
fcb4eea8 196 printf("{ b:%lX e:%lX pb: %lX r:%lX l:%lX %s %s %s} ",
3366b9c0
MD
197 (unsigned long) node->begin,
198 (unsigned long) node->end,
199 (unsigned long) get_parent(node)->begin,
fcb4eea8
MD
200 (unsigned long) node->_right->begin,
201 (unsigned long) node->_left->begin,
dff86257 202 node->color ? "red" : "black",
7ba89e62 203 get_pos(node) ? "right" : "left",
a84e8c8e 204 rcu_rbtree_is_nil(rbtree, node) ? "nil" : "");
dff86257
MD
205 node = rcu_rbtree_next(rbtree, node);
206 }
207 printf("\n");
208}
5d2c985d
MD
209#else /* DEBUG */
210static
211void show_tree(struct rcu_rbtree *rbtree)
212{
213}
214#endif /* DEBUG */
dff86257
MD
215
216static
217struct rcu_rbtree_node *make_nil(struct rcu_rbtree *rbtree)
218{
219 return &rbtree->nil_node;
220}
221
222/*
223 * Iterative rbtree search.
224 */
00539351 225struct rcu_rbtree_node *rcu_rbtree_search(struct rcu_rbtree *rbtree,
dff86257
MD
226 struct rcu_rbtree_node *x,
227 void *k)
228{
229 x = rcu_dereference(x);
ac5f3963 230 int comp;
dff86257 231
3366b9c0 232 while (!rcu_rbtree_is_nil(rbtree, x) && (comp = rbtree->comp(k, x->begin)) != 0) {
9c161ee1 233 dbg_usleep(10);
ac5f3963 234 if (comp < 0)
dca45c9f 235 x = rcu_dereference(x->_left);
dff86257 236 else
dca45c9f 237 x = rcu_dereference(x->_right);
dff86257
MD
238 }
239 return x;
240}
241
230dd288
MD
242static
243struct rcu_rbtree_node *rcu_rbtree_min_dup_decay(struct rcu_rbtree *rbtree,
244 struct rcu_rbtree_node *x,
245 struct rcu_rbtree_node **zr)
246{
247 struct rcu_rbtree_node *xl;
248
249 x = rcu_dereference(x);
250
8ded5fe9 251 if (rcu_rbtree_is_nil(rbtree, x)) {
230dd288
MD
252 *zr = x;
253 return x;
254 } else
255 *zr = x = dup_decay_node(rbtree, x);
256
8ded5fe9 257 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left))) {
230dd288 258 x = dup_decay_node(rbtree, xl);
7ba89e62 259 set_parent(x, get_decay(get_parent(x)), get_pos(x));
dca45c9f 260 get_parent(x)->_left = get_decay(get_parent(x)->_left);
230dd288
MD
261 }
262 return x;
263}
264
265static
266struct rcu_rbtree_node *rcu_rbtree_min_update_decay(struct rcu_rbtree *rbtree,
267 struct rcu_rbtree_node *x)
268{
269 struct rcu_rbtree_node *xl;
270
271 x = rcu_dereference(x);
272
8ded5fe9 273 if (rcu_rbtree_is_nil(rbtree, x))
230dd288
MD
274 return x;
275 else {
dca45c9f
MD
276 set_parent(x->_right, get_decay(get_parent(x->_right)),
277 get_pos(x->_right));
278 set_parent(x->_left, get_decay(get_parent(x->_left)),
279 get_pos(x->_left));
230dd288
MD
280 }
281
8ded5fe9 282 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left))) {
230dd288 283 x = xl;
dca45c9f
MD
284 set_parent(x->_right, get_decay(get_parent(x->_right)),
285 get_pos(x->_right));
286 set_parent(x->_left, get_decay(get_parent(x->_left)),
287 get_pos(x->_left));
230dd288
MD
288 }
289 return x;
290}
291
dff86257
MD
292struct rcu_rbtree_node *rcu_rbtree_min(struct rcu_rbtree *rbtree,
293 struct rcu_rbtree_node *x)
294{
295 struct rcu_rbtree_node *xl;
296
297 x = rcu_dereference(x);
298
8ded5fe9 299 if (rcu_rbtree_is_nil(rbtree, x))
dff86257
MD
300 return x;
301
8ded5fe9 302 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left)))
dff86257
MD
303 x = xl;
304 return x;
305}
306
307struct rcu_rbtree_node *rcu_rbtree_max(struct rcu_rbtree *rbtree,
308 struct rcu_rbtree_node *x)
309{
310 struct rcu_rbtree_node *xr;
311
312 x = rcu_dereference(x);
313
8ded5fe9 314 if (rcu_rbtree_is_nil(rbtree, x))
dff86257
MD
315 return x;
316
8ded5fe9 317 while (!rcu_rbtree_is_nil(rbtree, xr = rcu_dereference(x->_right)))
dff86257
MD
318 x = xr;
319 return x;
320}
321
322/*
323 * FIXME:
324 * Updates should wait for a grace period between update of the
325 * redirect pointer and update of the parent child pointer. This is to make sure
326 * that no reference to the old entry exist.
327 */
328
329/*
7ba89e62
MD
330 * RCU read lock must be held across the next/prev calls to ensure validity of
331 * the returned node.
dff86257
MD
332 */
333struct rcu_rbtree_node *rcu_rbtree_next(struct rcu_rbtree *rbtree,
334 struct rcu_rbtree_node *x)
335{
269a9ef6 336 struct rcu_rbtree_node *xr, *y;
7ba89e62 337 unsigned int x_pos;
dff86257
MD
338
339 x = rcu_dereference(x);
340
8ded5fe9 341 if (!rcu_rbtree_is_nil(rbtree, xr = rcu_dereference(x->_right)))
dff86257 342 return rcu_rbtree_min(rbtree, xr);
7ba89e62 343 y = get_parent_and_pos(x, &x_pos);
8ded5fe9 344 while (!rcu_rbtree_is_nil(rbtree, y) && x_pos == IS_RIGHT) {
dff86257 345 x = y;
7ba89e62 346 y = get_parent_and_pos(y, &x_pos);
dff86257
MD
347 }
348 return y;
349}
350
351struct rcu_rbtree_node *rcu_rbtree_prev(struct rcu_rbtree *rbtree,
352 struct rcu_rbtree_node *x)
353{
269a9ef6 354 struct rcu_rbtree_node *xl, *y;
7ba89e62 355 unsigned int x_pos;
dff86257
MD
356
357 x = rcu_dereference(x);
358
8ded5fe9 359 if (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left)))
4aa30442 360 return rcu_rbtree_max(rbtree, xl);
7ba89e62 361 y = get_parent_and_pos(x, &x_pos);
8ded5fe9 362 while (!rcu_rbtree_is_nil(rbtree, y) && x_pos == IS_LEFT) {
dff86257 363 x = y;
7ba89e62 364 y = get_parent_and_pos(y, &x_pos);
dff86257
MD
365 }
366 return y;
367}
368
7bc64d1d
MD
369/*
370 * "node" needs to be non-visible by readers.
371 */
372static
373void populate_node_end(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node,
fcb4eea8 374 unsigned int copy_parents, struct rcu_rbtree_node *stop)
7bc64d1d
MD
375{
376 struct rcu_rbtree_node *prev = NULL, *orig_node = node, *top;
377
378 do {
379 void *max_end;
380
fcb4eea8 381 assert(node);
7bc64d1d
MD
382 assert(!rcu_rbtree_is_nil(rbtree, node));
383 max_end = node->end;
384 if (!rcu_rbtree_is_nil(rbtree, node->_right))
385 max_end = max(max_end, node->_right->max_end);
386 if (!rcu_rbtree_is_nil(rbtree, node->_left))
387 max_end = max(max_end, node->_left->max_end);
388
389 if (max_end != node->max_end) {
fcb4eea8 390 if (prev && copy_parents) {
7bc64d1d
MD
391 node = dup_decay_node(rbtree, node);
392 if (get_pos(prev) == IS_RIGHT)
393 node->_right = prev;
394 else
395 node->_left = prev;
396 set_parent(prev, node, get_pos(prev));
397 }
398 node->max_end = max_end;
399 } else {
400 /*
401 * We did not have to change the current node,
402 * so set the pointer to the prev node. If prev
403 * was null, this means we are coming in the
404 * first loop, and must update the parent of the
405 * node received as parameter (node).
406 */
407 if (prev)
408 node = prev;
409 top = get_parent(node);
410 cmm_smp_wmb(); /* write into node before publish */
411 /* make new branch visible to readers */
412 if (rcu_rbtree_is_nil(rbtree, top))
413 _CMM_STORE_SHARED(rbtree->root, node);
414 if (get_pos(node) == IS_LEFT)
415 _CMM_STORE_SHARED(top->_left, node);
416 else
417 _CMM_STORE_SHARED(top->_right, node);
418 goto end;
419 }
fcb4eea8
MD
420
421 /* Check for propagation stop */
422 if (node == stop)
423 return;
424
7bc64d1d 425 prev = node;
fcb4eea8
MD
426 node = get_parent(node);
427 } while (!rcu_rbtree_is_nil(rbtree, node));
7bc64d1d
MD
428
429 top = node; /* nil */
430 cmm_smp_wmb(); /* write into node before publish */
431 /* make new branch visible to readers */
432 _CMM_STORE_SHARED(rbtree->root, prev);
433
434end:
fcb4eea8
MD
435 if (!copy_parents)
436 return;
7bc64d1d
MD
437 /* update children */
438 node = orig_node;
439 do {
440 assert(!rcu_rbtree_is_nil(rbtree, node));
441 set_parent(node->_left, get_decay(get_parent(node->_left)), IS_LEFT);
442 set_parent(node->_right, get_decay(get_parent(node->_right)), IS_RIGHT);
443 } while ((node = get_parent(node)) != top);
444}
445
dff86257
MD
446/*
447 * We have to ensure these assumptions are correct for prev/next
448 * traversal:
449 *
450 * with x being a right child, the assumption that:
dca45c9f 451 * get_parent(x)->_right == x
dff86257 452 * or if x is a left child, the assumption that:
dca45c9f 453 * get_parent(x)->_left == x
dff86257
MD
454 *
455 * This explains why we have to allocate a vc copy of the node for left_rotate,
456 * right_rotate and transplant operations.
457 *
458 * We always ensure that the right/left child and correct parent is set in the
459 * node copies *before* we reparent the children and make the upper-level point
460 * to the copy.
461 */
462
463/* RCU: copy x and y, atomically point to new versions. GC old. */
464/* Should be eventually followed by a cmm_smp_wmc() */
dff86257 465
dbe4ae98
MD
466#ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
467
dff86257 468static
269a9ef6
MD
469void left_rotate(struct rcu_rbtree *rbtree,
470 struct rcu_rbtree_node *x)
dff86257 471{
a84e8c8e 472 struct rcu_rbtree_node *y, *y_left;
dff86257 473
dca45c9f
MD
474 y = x->_right;
475 y_left = y->_left;
269a9ef6
MD
476
477 /* Now operate on new copy, decay old versions */
dbe4ae98
MD
478 x = dup_decay_node(rbtree, x);
479 y = dup_decay_node(rbtree, y);
480 y_left = dup_decay_node(rbtree, y_left);
269a9ef6 481
676dd8b6 482 /* Internal node modifications */
7ba89e62
MD
483 set_parent(y, get_parent(x), get_pos(x));
484 set_parent(x, y, IS_LEFT);
a84e8c8e
MD
485 set_left(rbtree, y, x);
486 set_right(rbtree, x, y_left);
dca45c9f 487
8ded5fe9 488 if (!rcu_rbtree_is_nil(rbtree, y_left))
7ba89e62 489 set_parent(y_left, x, IS_RIGHT);
676dd8b6
MD
490
491 cmm_smp_wmb(); /* write into node before publish */
492
493 /* External references update (visible by readers) */
a84e8c8e
MD
494 if (rcu_rbtree_is_nil(rbtree, get_parent(y)))
495 _CMM_STORE_SHARED(rbtree->root, y);
496 else if (get_pos(y) == IS_LEFT)
497 _CMM_STORE_SHARED(get_parent(y)->_left, y);
676dd8b6 498 else
a84e8c8e 499 _CMM_STORE_SHARED(get_parent(y)->_right, y);
676dd8b6 500
dbe4ae98 501 /* Point children to new copy (parent only used by updates/next/prev) */
dca45c9f
MD
502 set_parent(x->_left, get_decay(get_parent(x->_left)),
503 get_pos(x->_left));
504 set_parent(y->_right, get_decay(get_parent(y->_right)),
505 get_pos(y->_right));
8ded5fe9 506 if (!rcu_rbtree_is_nil(rbtree, y_left)) {
dca45c9f
MD
507 set_parent(y_left->_right,
508 get_decay(get_parent(y_left->_right)),
509 get_pos(y_left->_right));
510 set_parent(y_left->_left,
511 get_decay(get_parent(y_left->_left)),
512 get_pos(y_left->_left));
dbe4ae98 513 }
269a9ef6
MD
514
515 /* Sanity checks */
dca45c9f
MD
516 assert(y == rbtree->root || get_parent(y)->_left == y
517 || get_parent(y)->_right == y);
518 assert(x == rbtree->root || get_parent(x)->_left == x
519 || get_parent(x)->_right == x);
8ded5fe9
MD
520 assert(rcu_rbtree_is_nil(rbtree, x->_right) || get_parent(x->_right) == x);
521 assert(rcu_rbtree_is_nil(rbtree, x->_left) || get_parent(x->_left) == x);
522 assert(rcu_rbtree_is_nil(rbtree, y->_right) || get_parent(y->_right) == y);
523 assert(rcu_rbtree_is_nil(rbtree, y->_left) || get_parent(y->_left) == y);
269a9ef6
MD
524 assert(!is_decay(rbtree->root));
525 assert(!is_decay(x));
526 assert(!is_decay(y));
dca45c9f
MD
527 assert(!is_decay(x->_right));
528 assert(!is_decay(x->_left));
529 assert(!is_decay(y->_right));
530 assert(!is_decay(y->_left));
dff86257
MD
531}
532
dbe4ae98
MD
533#else
534
535/* non-rcu version */
536static
537void left_rotate(struct rcu_rbtree *rbtree,
538 struct rcu_rbtree_node *x)
539{
540 struct rcu_rbtree_node *y;
541
230dd288 542 lock_test_mutex();
dca45c9f
MD
543 y = x->_right;
544 x->_right = y->_left;
8ded5fe9 545 if (!rcu_rbtree_is_nil(rbtree, y->_left))
dca45c9f 546 set_parent(y->_left, x, IS_RIGHT);
7ba89e62 547 set_parent(y, get_parent(x), get_pos(x));
8ded5fe9 548 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
dbe4ae98 549 rbtree->root = y;
dca45c9f
MD
550 else if (x == get_parent(x)->_left) {
551 get_parent(x)->_left = y;
dbe4ae98 552 } else {
dca45c9f 553 get_parent(x)->_right = y;
dbe4ae98 554 }
dca45c9f 555 y->_left = x;
7ba89e62 556 set_parent(x, y, IS_LEFT);
230dd288 557 unlock_test_mutex();
dbe4ae98
MD
558}
559
560#endif
561
562#ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
dff86257 563static
269a9ef6
MD
564void right_rotate(struct rcu_rbtree *rbtree,
565 struct rcu_rbtree_node *x)
dff86257 566{
a84e8c8e 567 struct rcu_rbtree_node *y, *y_right;
dff86257 568
dca45c9f
MD
569 y = x->_left;
570 y_right = y->_right;
269a9ef6
MD
571
572 /* Now operate on new copy, decay old versions */
dbe4ae98
MD
573 x = dup_decay_node(rbtree, x);
574 y = dup_decay_node(rbtree, y);
575 y_right = dup_decay_node(rbtree, y_right);
269a9ef6 576
676dd8b6 577 /* Internal node modifications */
7ba89e62
MD
578 set_parent(y, get_parent(x), get_pos(x));
579 set_parent(x, y, IS_RIGHT);
a84e8c8e
MD
580 set_right(rbtree, y, x);
581 set_left(rbtree, x, y_right);
dca45c9f 582
8ded5fe9 583 if (!rcu_rbtree_is_nil(rbtree, y_right))
7ba89e62 584 set_parent(y_right, x, IS_LEFT);
676dd8b6
MD
585
586 cmm_smp_wmb(); /* write into node before publish */
587
588 /* External references update (visible by readers) */
a84e8c8e
MD
589 if (rcu_rbtree_is_nil(rbtree, get_parent(y)))
590 _CMM_STORE_SHARED(rbtree->root, y);
591 else if (get_pos(y) == IS_RIGHT)
592 _CMM_STORE_SHARED(get_parent(y)->_right, y);
676dd8b6 593 else
a84e8c8e 594 _CMM_STORE_SHARED(get_parent(y)->_left, y);
676dd8b6 595
dbe4ae98 596 /* Point children to new copy (parent only used by updates/next/prev) */
dca45c9f
MD
597 set_parent(x->_right, get_decay(get_parent(x->_right)),
598 get_pos(x->_right));
599 set_parent(y->_left, get_decay(get_parent(y->_left)),
600 get_pos(y->_left));
8ded5fe9 601 if (!rcu_rbtree_is_nil(rbtree, y_right)) {
dca45c9f
MD
602 set_parent(y_right->_left,
603 get_decay(get_parent(y_right->_left)),
604 get_pos(y_right->_left));
605 set_parent(y_right->_right,
606 get_decay(get_parent(y_right->_right)),
607 get_pos(y_right->_right));
dbe4ae98 608 }
269a9ef6
MD
609
610 /* Sanity checks */
dca45c9f
MD
611 assert(y == rbtree->root || get_parent(y)->_right == y
612 || get_parent(y)->_left == y);
613 assert(x == rbtree->root || get_parent(x)->_right == x
614 || get_parent(x)->_left == x);
8ded5fe9
MD
615 assert(rcu_rbtree_is_nil(rbtree, x->_left) || get_parent(x->_left) == x);
616 assert(rcu_rbtree_is_nil(rbtree, x->_right) || get_parent(x->_right) == x);
617 assert(rcu_rbtree_is_nil(rbtree, y->_left) || get_parent(y->_left) == y);
618 assert(rcu_rbtree_is_nil(rbtree, y->_right) || get_parent(y->_right) == y);
269a9ef6
MD
619 assert(!is_decay(rbtree->root));
620 assert(!is_decay(x));
621 assert(!is_decay(y));
dca45c9f
MD
622 assert(!is_decay(x->_left));
623 assert(!is_decay(x->_right));
624 assert(!is_decay(y->_left));
625 assert(!is_decay(y->_right));
dff86257
MD
626}
627
6daf6090
MD
628#else
629
dbe4ae98 630/* non-rcu version */
6daf6090
MD
631static
632void right_rotate(struct rcu_rbtree *rbtree,
633 struct rcu_rbtree_node *x)
634{
635 struct rcu_rbtree_node *y;
636
230dd288 637 lock_test_mutex();
dca45c9f
MD
638 y = x->_left;
639 x->_left = y->_right;
8ded5fe9 640 if (!rcu_rbtree_is_nil(rbtree, y->_right))
dca45c9f 641 set_parent(y->_right, x, IS_LEFT);
7ba89e62 642 set_parent(y, get_parent(x), get_pos(x));
8ded5fe9 643 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
6daf6090 644 rbtree->root = y;
dca45c9f
MD
645 else if (x == get_parent(x)->_right) {
646 get_parent(x)->_right = y;
6daf6090 647 } else {
dca45c9f 648 get_parent(x)->_left = y;
6daf6090 649 }
dca45c9f 650 y->_right = x;
7ba89e62 651 set_parent(x, y, IS_RIGHT);
230dd288 652 unlock_test_mutex();
6daf6090
MD
653}
654
655#endif
656
dff86257
MD
657static void rcu_rbtree_insert_fixup(struct rcu_rbtree *rbtree,
658 struct rcu_rbtree_node *z)
659{
660 struct rcu_rbtree_node *y;
661
3366b9c0 662 dbg_printf("insert fixup %p\n", z->begin);
269a9ef6 663 assert(!is_decay(rbtree->root));
dff86257 664
7ba89e62 665 while (get_parent(z)->color == COLOR_RED) {
dca45c9f
MD
666 if (get_parent(z) == get_parent(get_parent(z))->_left) {
667 y = get_parent(get_parent(z))->_right;
dff86257 668 if (y->color == COLOR_RED) {
7ba89e62 669 get_parent(z)->color = COLOR_BLACK;
dff86257 670 y->color = COLOR_BLACK;
7ba89e62
MD
671 get_parent(get_parent(z))->color = COLOR_RED;
672 z = get_parent(get_parent(z));
dff86257 673 } else {
dca45c9f 674 if (z == get_parent(z)->_right) {
7ba89e62 675 z = get_parent(z);
dff86257 676 left_rotate(rbtree, z);
269a9ef6
MD
677 z = get_decay(z);
678 assert(!is_decay(rbtree->root));
dff86257 679 }
7ba89e62
MD
680 get_parent(z)->color = COLOR_BLACK;
681 get_parent(get_parent(z))->color = COLOR_RED;
269a9ef6 682 assert(!is_decay(z));
7ba89e62
MD
683 assert(!is_decay(get_parent(z)));
684 assert(!is_decay(get_parent(get_parent(z))));
685 right_rotate(rbtree, get_parent(get_parent(z)));
269a9ef6
MD
686 assert(!is_decay(z));
687 assert(!is_decay(rbtree->root));
dff86257
MD
688 }
689 } else {
dca45c9f 690 y = get_parent(get_parent(z))->_left;
dff86257 691 if (y->color == COLOR_RED) {
7ba89e62 692 get_parent(z)->color = COLOR_BLACK;
dff86257 693 y->color = COLOR_BLACK;
7ba89e62
MD
694 get_parent(get_parent(z))->color = COLOR_RED;
695 z = get_parent(get_parent(z));
dff86257 696 } else {
dca45c9f 697 if (z == get_parent(z)->_left) {
7ba89e62 698 z = get_parent(z);
dff86257 699 right_rotate(rbtree, z);
269a9ef6
MD
700 z = get_decay(z);
701 assert(!is_decay(rbtree->root));
dff86257 702 }
7ba89e62
MD
703 get_parent(z)->color = COLOR_BLACK;
704 get_parent(get_parent(z))->color = COLOR_RED;
705 left_rotate(rbtree, get_parent(get_parent(z)));
269a9ef6
MD
706 assert(!is_decay(z));
707 assert(!is_decay(rbtree->root));
dff86257
MD
708 }
709 }
710 }
711 rbtree->root->color = COLOR_BLACK;
712}
713
714/*
715 * rcu_rbtree_insert - Insert a node in the RCU rbtree
716 *
717 * Returns 0 on success, or < 0 on error.
718 */
719int rcu_rbtree_insert(struct rcu_rbtree *rbtree,
720 struct rcu_rbtree_node *z)
721{
a84e8c8e 722 struct rcu_rbtree_node *x, *y;
dff86257 723
3366b9c0 724 dbg_printf("insert %p\n", z->begin);
269a9ef6 725 assert(!is_decay(rbtree->root));
dff86257
MD
726
727 y = make_nil(rbtree);
dff86257 728 x = rbtree->root;
8ded5fe9 729 while (!rcu_rbtree_is_nil(rbtree, x)) {
dff86257 730 y = x;
3366b9c0 731 if (rbtree->comp(z->begin, x->begin) < 0)
dca45c9f 732 x = x->_left;
dff86257 733 else
dca45c9f 734 x = x->_right;
dff86257
MD
735 }
736
dca45c9f
MD
737 z->_left = make_nil(rbtree);
738 z->_right = make_nil(rbtree);
dff86257 739 z->color = COLOR_RED;
269a9ef6 740 z->decay_next = NULL;
55b5e812 741 z->max_end = z->end;
dff86257 742
8ded5fe9 743 if (rcu_rbtree_is_nil(rbtree, y)) {
7bc64d1d 744 set_parent(z, y, IS_RIGHT); /* pos arbitrary for root node */
0bd215cc
MD
745 /*
746 * Order stores to z (children/parents) before stores
747 * that will make it visible to the rest of the tree.
748 */
749 cmm_smp_wmb();
dff86257 750 _CMM_STORE_SHARED(rbtree->root, z);
3366b9c0 751 } else if (rbtree->comp(z->begin, y->begin) < 0) {
7bc64d1d
MD
752 y = dup_decay_node(rbtree, y);
753 set_parent(z, y, IS_LEFT);
754 if (get_pos(z) == IS_LEFT)
a84e8c8e 755 _CMM_STORE_SHARED(y->_left, z);
dca45c9f 756 else
a84e8c8e 757 _CMM_STORE_SHARED(y->_right, z);
fcb4eea8 758 populate_node_end(rbtree, y, 1, NULL);
dca45c9f 759 } else {
7bc64d1d
MD
760 y = dup_decay_node(rbtree, y);
761 set_parent(z, y, IS_RIGHT);
762 if (get_pos(z) == IS_LEFT)
a84e8c8e 763 _CMM_STORE_SHARED(y->_left, z);
dca45c9f 764 else
a84e8c8e 765 _CMM_STORE_SHARED(y->_right, z);
fcb4eea8 766 populate_node_end(rbtree, y, 1, NULL);
dca45c9f 767 }
dff86257
MD
768 rcu_rbtree_insert_fixup(rbtree, z);
769 /*
770 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
771 */
772 cmm_smp_wmc();
773 show_tree(rbtree);
774
775 return 0;
776}
777
778/*
779 * Transplant v into u position.
dff86257 780 */
6daf6090
MD
781
782#ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
783
269a9ef6
MD
784static
785void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
786 struct rcu_rbtree_node *u,
dca45c9f 787 struct rcu_rbtree_node *v,
fcb4eea8
MD
788 unsigned int copy_parents,
789 struct rcu_rbtree_node *stop)
dff86257 790{
3366b9c0 791 dbg_printf("transplant %p\n", v->begin);
dff86257 792
8ded5fe9 793 if (!rcu_rbtree_is_nil(rbtree, v))
dbe4ae98 794 v = dup_decay_node(rbtree, v);
c479601c 795
8ded5fe9 796 if (rcu_rbtree_is_nil(rbtree, get_parent(u))) {
7ba89e62
MD
797 /* pos is arbitrary for root node */
798 set_parent(v, get_parent(u), IS_RIGHT);
c479601c
MD
799 cmm_smp_wmb(); /* write into node before publish */
800 _CMM_STORE_SHARED(rbtree->root, v);
dff86257 801 } else {
fcb4eea8
MD
802 struct rcu_rbtree_node *vp;
803
804 vp = get_parent(u);
805 if (copy_parents)
806 vp = dup_decay_node(rbtree, vp);
807 set_parent(v, vp, get_pos(u));
808 if (get_pos(v) == IS_LEFT)
809 _CMM_STORE_SHARED(vp->_left, v);
806967f3 810 else
fcb4eea8
MD
811 _CMM_STORE_SHARED(vp->_right, v);
812 populate_node_end(rbtree, vp, copy_parents, stop);
c479601c 813 }
806967f3 814
dbe4ae98 815 /* Point children to new copy (parent only used by updates/next/prev) */
8ded5fe9 816 if (!rcu_rbtree_is_nil(rbtree, v)) {
dca45c9f
MD
817 set_parent(v->_right, get_decay(get_parent(v->_right)),
818 get_pos(v->_right));
819 set_parent(v->_left, get_decay(get_parent(v->_left)),
820 get_pos(v->_left));
dff86257 821 }
269a9ef6 822 assert(!is_decay(rbtree->root));
dff86257
MD
823}
824
6daf6090
MD
825#else
826
827/* Non-RCU version */
828static
829void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
830 struct rcu_rbtree_node *u,
dca45c9f 831 struct rcu_rbtree_node *v,
fcb4eea8
MD
832 unsigned int copy_parents,
833 struct rcu_rbtree_node *stop)
6daf6090 834{
3366b9c0 835 dbg_printf("transplant %p\n", v->begin);
6daf6090 836
230dd288 837 lock_test_mutex();
8ded5fe9 838 if (rcu_rbtree_is_nil(rbtree, get_parent(u)))
6daf6090 839 rbtree->root = v;
dca45c9f
MD
840 else if (u == get_parent(u)->_left)
841 get_parent(u)->_left = v;
7ba89e62 842 else
dca45c9f 843 get_parent(u)->_right = v;
7ba89e62 844 set_parent(v, get_parent(u), get_pos(u));
230dd288 845 unlock_test_mutex();
6daf6090
MD
846}
847
848#endif
849
dff86257
MD
850static void rcu_rbtree_remove_fixup(struct rcu_rbtree *rbtree,
851 struct rcu_rbtree_node *x)
852{
3366b9c0 853 dbg_printf("remove fixup %p\n", x->begin);
dff86257
MD
854
855 while (x != rbtree->root && x->color == COLOR_BLACK) {
7ba89e62 856 assert(!is_decay(get_parent(x)));
dca45c9f
MD
857 assert(!is_decay(get_parent(x)->_left));
858 if (x == get_parent(x)->_left) {
269a9ef6 859 struct rcu_rbtree_node *w;
dff86257 860
dca45c9f 861 w = get_parent(x)->_right;
dff86257
MD
862
863 if (w->color == COLOR_RED) {
269a9ef6 864 w->color = COLOR_BLACK;
7ba89e62
MD
865 get_parent(x)->color = COLOR_RED;
866 left_rotate(rbtree, get_parent(x));
269a9ef6
MD
867 x = get_decay(x);
868 assert(!is_decay(rbtree->root));
dca45c9f 869 w = get_parent(x)->_right;
dff86257 870 }
dca45c9f
MD
871 if (w->_left->color == COLOR_BLACK
872 && w->_right->color == COLOR_BLACK) {
dff86257 873 w->color = COLOR_RED;
7ba89e62 874 x = get_parent(x);
c479601c
MD
875 assert(!is_decay(rbtree->root));
876 assert(!is_decay(x));
dff86257 877 } else {
dca45c9f
MD
878 if (w->_right->color == COLOR_BLACK) {
879 w->_left->color = COLOR_BLACK;
dff86257
MD
880 w->color = COLOR_RED;
881 right_rotate(rbtree, w);
c479601c 882 assert(!is_decay(rbtree->root));
269a9ef6 883 x = get_decay(x);
dca45c9f 884 w = get_parent(x)->_right;
dff86257 885 }
7ba89e62
MD
886 w->color = get_parent(x)->color;
887 get_parent(x)->color = COLOR_BLACK;
dca45c9f 888 w->_right->color = COLOR_BLACK;
7ba89e62 889 left_rotate(rbtree, get_parent(x));
269a9ef6 890 assert(!is_decay(rbtree->root));
dff86257
MD
891 x = rbtree->root;
892 }
893 } else {
269a9ef6 894 struct rcu_rbtree_node *w;
dff86257 895
dca45c9f 896 w = get_parent(x)->_left;
dff86257
MD
897
898 if (w->color == COLOR_RED) {
269a9ef6 899 w->color = COLOR_BLACK;
7ba89e62
MD
900 get_parent(x)->color = COLOR_RED;
901 right_rotate(rbtree, get_parent(x));
c479601c 902 assert(!is_decay(rbtree->root));
269a9ef6 903 x = get_decay(x);
dca45c9f 904 w = get_parent(x)->_left;
dff86257 905 }
dca45c9f
MD
906 if (w->_right->color == COLOR_BLACK
907 && w->_left->color == COLOR_BLACK) {
dff86257 908 w->color = COLOR_RED;
7ba89e62 909 x = get_parent(x);
c479601c
MD
910 assert(!is_decay(rbtree->root));
911 assert(!is_decay(x));
dff86257 912 } else {
dca45c9f
MD
913 if (w->_left->color == COLOR_BLACK) {
914 w->_right->color = COLOR_BLACK;
dff86257
MD
915 w->color = COLOR_RED;
916 left_rotate(rbtree, w);
269a9ef6
MD
917 assert(!is_decay(rbtree->root));
918 x = get_decay(x);
dca45c9f 919 w = get_parent(x)->_left;
dff86257 920 }
7ba89e62
MD
921 w->color = get_parent(x)->color;
922 get_parent(x)->color = COLOR_BLACK;
dca45c9f 923 w->_left->color = COLOR_BLACK;
7ba89e62 924 right_rotate(rbtree, get_parent(x));
c479601c 925 assert(!is_decay(rbtree->root));
dff86257
MD
926 x = rbtree->root;
927 }
928 }
929 }
930 x->color = COLOR_BLACK;
931}
932
933/*
269a9ef6
MD
934 * Delete z. All non-copied children left/right positions are unchanged.
935 */
936static
937void rcu_rbtree_remove_nonil(struct rcu_rbtree *rbtree,
938 struct rcu_rbtree_node *z,
939 struct rcu_rbtree_node *y)
dff86257 940{
a84e8c8e 941 struct rcu_rbtree_node *x;
dff86257 942
3366b9c0 943 dbg_printf("remove nonil %p\n", z->begin);
dff86257
MD
944 show_tree(rbtree);
945
c479601c
MD
946 assert(!is_decay(z));
947 assert(!is_decay(y));
dca45c9f 948 assert(!is_decay(y->_right));
7ba89e62 949 assert(!is_decay(get_parent(y)));
dca45c9f 950 x = y->_right;
c479601c 951 assert(!is_decay(x));
7ba89e62 952 if (get_parent(y) == z) {
230dd288 953 y = dup_decay_node(rbtree, y);
7ba89e62 954 set_parent(x, y, get_pos(x)); /* parent for nil */
dca45c9f 955 /* y is z's right node: set left will just update y */
a84e8c8e 956 set_left(rbtree, y, z->_left);
fcb4eea8 957 rcu_rbtree_transplant(rbtree, z, y, 1, NULL);
230dd288
MD
958 } else {
959 struct rcu_rbtree_node *oy_right, *z_right;
960
961 /*
962 * Need to make sure y is always visible by readers.
963 */
dca45c9f 964 y = rcu_rbtree_min_dup_decay(rbtree, z->_right, &z_right);
269a9ef6
MD
965 assert(!is_decay(y));
966 assert(!is_decay(z));
dca45c9f
MD
967 oy_right = y->_right;
968
969 /*
3366b9c0 970 * The max child begin of z_right does not change, because
dca45c9f
MD
971 * we're only changing its left children.
972 */
973 y->_right = z_right;
974 set_parent(y->_right, y, IS_RIGHT);
dca45c9f
MD
975 assert(!is_decay(z->_left));
976 y->_left = z->_left;
230dd288 977 assert(!is_decay(oy_right));
dca45c9f
MD
978 /*
979 * Transplant of oy_right to old y's location will only
fcb4eea8 980 * trigger a "end" value update of the already copied branch
dca45c9f
MD
981 * (which is not visible yet). We are transplanting
982 * oy_right as a left child of old y's parent, so the
983 * min values update propagated upward necessarily stops
984 * at z_right.
985 */
fcb4eea8
MD
986 rcu_rbtree_transplant(rbtree, y, oy_right, 0, y);
987 rcu_rbtree_transplant(rbtree, z, y, 1, NULL);
230dd288 988 /* Update children */
dca45c9f 989 (void) rcu_rbtree_min_update_decay(rbtree, y->_right);
dff86257 990 }
c479601c 991 y = get_decay(y);
269a9ef6 992 assert(!is_decay(z));
dca45c9f 993 assert(!is_decay(z->_left));
dff86257 994 y->color = z->color;
dca45c9f
MD
995 set_parent(y->_left, y, IS_LEFT);
996 set_parent(y->_right, get_decay(get_parent(y->_right)), IS_RIGHT);
997 assert(!is_decay(y->_left));
998 assert(!is_decay(y->_right));
dff86257
MD
999}
1000
1001int rcu_rbtree_remove(struct rcu_rbtree *rbtree,
1002 struct rcu_rbtree_node *z)
1003{
1004 struct rcu_rbtree_node *x, *y;
1005 unsigned int y_original_color;
1006
269a9ef6 1007 assert(!is_decay(rbtree->root));
3366b9c0 1008 dbg_printf("remove %p\n", z->begin);
dff86257
MD
1009 show_tree(rbtree);
1010
c479601c 1011 assert(!is_decay(z));
dff86257
MD
1012 y = z;
1013 y_original_color = y->color;
1014
8ded5fe9 1015 if (rcu_rbtree_is_nil(rbtree, z->_left)) {
fcb4eea8 1016 rcu_rbtree_transplant(rbtree, z, z->_right, 1, NULL);
269a9ef6 1017 assert(!is_decay(z));
dca45c9f 1018 x = get_decay(z->_right);
dff86257 1019 show_tree(rbtree);
8ded5fe9 1020 } else if (rcu_rbtree_is_nil(rbtree, z->_right)) {
fcb4eea8 1021 rcu_rbtree_transplant(rbtree, z, z->_left, 1, NULL);
269a9ef6 1022 assert(!is_decay(z));
dca45c9f 1023 x = get_decay(z->_left);
dff86257
MD
1024 show_tree(rbtree);
1025 } else {
dca45c9f 1026 y = rcu_rbtree_min(rbtree, z->_right);
c479601c 1027 assert(!is_decay(y));
dff86257 1028 y_original_color = y->color;
dca45c9f 1029 x = y->_right;
269a9ef6 1030 rcu_rbtree_remove_nonil(rbtree, z, y);
6daf6090 1031 x = get_decay(x);
dff86257
MD
1032 show_tree(rbtree);
1033 }
1034 if (y_original_color == COLOR_BLACK)
1035 rcu_rbtree_remove_fixup(rbtree, x);
1036 show_tree(rbtree);
1037 /*
1038 * Commit all _CMM_STORE_SHARED().
1039 */
1040 cmm_smp_wmc();
1041
1042 return 0;
1043}
This page took 0.07199 seconds and 4 git commands to generate.