rbtree: Add end recalculation for transplant
[urcu.git] / urcu-rbtree.c
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>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include <urcu/rcurbtree.h>
40 #include <urcu-pointer.h>
41 #include <urcu-call-rcu.h>
42 #include <urcu/compiler.h>
43
44 #ifdef DEBUG
45 #define dbg_printf(args...) printf(args)
46 #define dbg_usleep(usecs) usleep(usecs)
47 #else
48 #define dbg_printf(args...)
49 #define dbg_usleep(usecs)
50 #endif
51
52 /*
53 * Undefine this to enable the non-RCU rotate and transplant functions
54 * (for debugging).
55 */
56 #define RBTREE_RCU_SUPPORT_ROTATE_LEFT
57 #define RBTREE_RCU_SUPPORT_ROTATE_RIGHT
58 #define RBTREE_RCU_SUPPORT_TRANSPLANT
59
60 #ifdef EXTRA_DEBUG
61 static pthread_mutex_t test_mutex = PTHREAD_MUTEX_INITIALIZER;
62 static pthread_mutex_t outer_mutex = PTHREAD_MUTEX_INITIALIZER;
63
64 static
65 void lock_outer_mutex(void)
66 {
67 pthread_mutex_lock(&outer_mutex);
68 }
69
70 static
71 void unlock_outer_mutex(void)
72 {
73 pthread_mutex_unlock(&outer_mutex);
74 }
75
76 static
77 void lock_test_mutex(void)
78 {
79 pthread_mutex_lock(&test_mutex);
80 }
81
82 static
83 void unlock_test_mutex(void)
84 {
85 pthread_mutex_unlock(&test_mutex);
86 }
87 #endif
88
89 static
90 void set_parent(struct rcu_rbtree_node *node,
91 struct rcu_rbtree_node *parent,
92 unsigned int pos)
93 {
94 _CMM_STORE_SHARED(node->parent, ((unsigned long) parent) | pos);
95 }
96
97 static
98 struct rcu_rbtree_node *get_parent(struct rcu_rbtree_node *node)
99 {
100 return (struct rcu_rbtree_node *) (node->parent & ~1UL);
101 }
102
103 static
104 unsigned int get_pos(struct rcu_rbtree_node *node)
105 {
106 return (unsigned int) (node->parent & 1UL);
107 }
108
109 static
110 struct 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
119 static
120 void set_decay(struct rcu_rbtree_node *x, struct rcu_rbtree_node *xc)
121 {
122 x->decay_next = xc;
123 }
124
125 static
126 struct rcu_rbtree_node *get_decay(struct rcu_rbtree_node *x)
127 {
128 if (!x)
129 return NULL;
130 while (x->decay_next)
131 x = x->decay_next;
132 return x;
133 }
134
135 static
136 struct rcu_rbtree_node *is_decay(struct rcu_rbtree_node *x)
137 {
138 return x->decay_next;
139 }
140
141 static
142 struct rcu_rbtree_node *dup_decay_node(struct rcu_rbtree *rbtree,
143 struct rcu_rbtree_node *x)
144 {
145 struct rcu_rbtree_node *xc;
146
147 if (rcu_rbtree_is_nil(rbtree, x))
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);
154 call_rcu(&x->head, rbtree->rbfree);
155 return xc;
156 }
157
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 */
165 static
166 void set_left(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node,
167 struct rcu_rbtree_node *left)
168 {
169 node->_left = left;
170 }
171
172 static
173 void set_right(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node,
174 struct rcu_rbtree_node *right)
175 {
176 node->_right = right;
177 }
178
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
187 #ifdef DEBUG
188 static
189 void show_tree(struct rcu_rbtree *rbtree)
190 {
191 struct rcu_rbtree_node *node;
192
193 node = rcu_rbtree_min(rbtree, rbtree->root);
194 while (!rcu_rbtree_is_nil(rbtree, node)) {
195 assert(!is_decay(node));
196 printf("{ b:%lX e:%lX pb: %lX r:%lX l:%lX %s %s %s} ",
197 (unsigned long) node->begin,
198 (unsigned long) node->end,
199 (unsigned long) get_parent(node)->begin,
200 (unsigned long) node->_right->begin,
201 (unsigned long) node->_left->begin,
202 node->color ? "red" : "black",
203 get_pos(node) ? "right" : "left",
204 rcu_rbtree_is_nil(rbtree, node) ? "nil" : "");
205 node = rcu_rbtree_next(rbtree, node);
206 }
207 printf("\n");
208 }
209 #else /* DEBUG */
210 static
211 void show_tree(struct rcu_rbtree *rbtree)
212 {
213 }
214 #endif /* DEBUG */
215
216 static
217 struct rcu_rbtree_node *make_nil(struct rcu_rbtree *rbtree)
218 {
219 return &rbtree->nil_node;
220 }
221
222 /*
223 * Iterative rbtree search.
224 */
225 struct rcu_rbtree_node *rcu_rbtree_search(struct rcu_rbtree *rbtree,
226 struct rcu_rbtree_node *x,
227 void *k)
228 {
229 x = rcu_dereference(x);
230 int comp;
231
232 while (!rcu_rbtree_is_nil(rbtree, x) && (comp = rbtree->comp(k, x->begin)) != 0) {
233 dbg_usleep(10);
234 if (comp < 0)
235 x = rcu_dereference(x->_left);
236 else
237 x = rcu_dereference(x->_right);
238 }
239 return x;
240 }
241
242 static
243 struct 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
251 if (rcu_rbtree_is_nil(rbtree, x)) {
252 *zr = x;
253 return x;
254 } else
255 *zr = x = dup_decay_node(rbtree, x);
256
257 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left))) {
258 x = dup_decay_node(rbtree, xl);
259 set_parent(x, get_decay(get_parent(x)), get_pos(x));
260 get_parent(x)->_left = get_decay(get_parent(x)->_left);
261 }
262 return x;
263 }
264
265 static
266 struct 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
273 if (rcu_rbtree_is_nil(rbtree, x))
274 return x;
275 else {
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));
280 }
281
282 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left))) {
283 x = xl;
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));
288 }
289 return x;
290 }
291
292 struct 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
299 if (rcu_rbtree_is_nil(rbtree, x))
300 return x;
301
302 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left)))
303 x = xl;
304 return x;
305 }
306
307 struct 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
314 if (rcu_rbtree_is_nil(rbtree, x))
315 return x;
316
317 while (!rcu_rbtree_is_nil(rbtree, xr = rcu_dereference(x->_right)))
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 /*
330 * RCU read lock must be held across the next/prev calls to ensure validity of
331 * the returned node.
332 */
333 struct rcu_rbtree_node *rcu_rbtree_next(struct rcu_rbtree *rbtree,
334 struct rcu_rbtree_node *x)
335 {
336 struct rcu_rbtree_node *xr, *y;
337 unsigned int x_pos;
338
339 x = rcu_dereference(x);
340
341 if (!rcu_rbtree_is_nil(rbtree, xr = rcu_dereference(x->_right)))
342 return rcu_rbtree_min(rbtree, xr);
343 y = get_parent_and_pos(x, &x_pos);
344 while (!rcu_rbtree_is_nil(rbtree, y) && x_pos == IS_RIGHT) {
345 x = y;
346 y = get_parent_and_pos(y, &x_pos);
347 }
348 return y;
349 }
350
351 struct rcu_rbtree_node *rcu_rbtree_prev(struct rcu_rbtree *rbtree,
352 struct rcu_rbtree_node *x)
353 {
354 struct rcu_rbtree_node *xl, *y;
355 unsigned int x_pos;
356
357 x = rcu_dereference(x);
358
359 if (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left)))
360 return rcu_rbtree_max(rbtree, xl);
361 y = get_parent_and_pos(x, &x_pos);
362 while (!rcu_rbtree_is_nil(rbtree, y) && x_pos == IS_LEFT) {
363 x = y;
364 y = get_parent_and_pos(y, &x_pos);
365 }
366 return y;
367 }
368
369 /*
370 * "node" needs to be non-visible by readers.
371 */
372 static
373 void populate_node_end(struct rcu_rbtree *rbtree, struct rcu_rbtree_node *node,
374 unsigned int copy_parents, struct rcu_rbtree_node *stop)
375 {
376 struct rcu_rbtree_node *prev = NULL, *orig_node = node, *top;
377
378 do {
379 void *max_end;
380
381 assert(node);
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) {
390 if (prev && copy_parents) {
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 }
420
421 /* Check for propagation stop */
422 if (node == stop)
423 return;
424
425 prev = node;
426 node = get_parent(node);
427 } while (!rcu_rbtree_is_nil(rbtree, node));
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
434 end:
435 if (!copy_parents)
436 return;
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
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:
451 * get_parent(x)->_right == x
452 * or if x is a left child, the assumption that:
453 * get_parent(x)->_left == x
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() */
465
466 #ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
467
468 static
469 void left_rotate(struct rcu_rbtree *rbtree,
470 struct rcu_rbtree_node *x)
471 {
472 struct rcu_rbtree_node *y, *y_left;
473
474 y = x->_right;
475 y_left = y->_left;
476
477 /* Now operate on new copy, decay old versions */
478 x = dup_decay_node(rbtree, x);
479 y = dup_decay_node(rbtree, y);
480 y_left = dup_decay_node(rbtree, y_left);
481
482 /* Internal node modifications */
483 set_parent(y, get_parent(x), get_pos(x));
484 set_parent(x, y, IS_LEFT);
485 set_left(rbtree, y, x);
486 set_right(rbtree, x, y_left);
487
488 if (!rcu_rbtree_is_nil(rbtree, y_left))
489 set_parent(y_left, x, IS_RIGHT);
490
491 cmm_smp_wmb(); /* write into node before publish */
492
493 /* External references update (visible by readers) */
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);
498 else
499 _CMM_STORE_SHARED(get_parent(y)->_right, y);
500
501 /* Point children to new copy (parent only used by updates/next/prev) */
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));
506 if (!rcu_rbtree_is_nil(rbtree, y_left)) {
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));
513 }
514
515 /* Sanity checks */
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);
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);
524 assert(!is_decay(rbtree->root));
525 assert(!is_decay(x));
526 assert(!is_decay(y));
527 assert(!is_decay(x->_right));
528 assert(!is_decay(x->_left));
529 assert(!is_decay(y->_right));
530 assert(!is_decay(y->_left));
531 }
532
533 #else
534
535 /* non-rcu version */
536 static
537 void left_rotate(struct rcu_rbtree *rbtree,
538 struct rcu_rbtree_node *x)
539 {
540 struct rcu_rbtree_node *y;
541
542 lock_test_mutex();
543 y = x->_right;
544 x->_right = y->_left;
545 if (!rcu_rbtree_is_nil(rbtree, y->_left))
546 set_parent(y->_left, x, IS_RIGHT);
547 set_parent(y, get_parent(x), get_pos(x));
548 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
549 rbtree->root = y;
550 else if (x == get_parent(x)->_left) {
551 get_parent(x)->_left = y;
552 } else {
553 get_parent(x)->_right = y;
554 }
555 y->_left = x;
556 set_parent(x, y, IS_LEFT);
557 unlock_test_mutex();
558 }
559
560 #endif
561
562 #ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
563 static
564 void right_rotate(struct rcu_rbtree *rbtree,
565 struct rcu_rbtree_node *x)
566 {
567 struct rcu_rbtree_node *y, *y_right;
568
569 y = x->_left;
570 y_right = y->_right;
571
572 /* Now operate on new copy, decay old versions */
573 x = dup_decay_node(rbtree, x);
574 y = dup_decay_node(rbtree, y);
575 y_right = dup_decay_node(rbtree, y_right);
576
577 /* Internal node modifications */
578 set_parent(y, get_parent(x), get_pos(x));
579 set_parent(x, y, IS_RIGHT);
580 set_right(rbtree, y, x);
581 set_left(rbtree, x, y_right);
582
583 if (!rcu_rbtree_is_nil(rbtree, y_right))
584 set_parent(y_right, x, IS_LEFT);
585
586 cmm_smp_wmb(); /* write into node before publish */
587
588 /* External references update (visible by readers) */
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);
593 else
594 _CMM_STORE_SHARED(get_parent(y)->_left, y);
595
596 /* Point children to new copy (parent only used by updates/next/prev) */
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));
601 if (!rcu_rbtree_is_nil(rbtree, y_right)) {
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));
608 }
609
610 /* Sanity checks */
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);
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);
619 assert(!is_decay(rbtree->root));
620 assert(!is_decay(x));
621 assert(!is_decay(y));
622 assert(!is_decay(x->_left));
623 assert(!is_decay(x->_right));
624 assert(!is_decay(y->_left));
625 assert(!is_decay(y->_right));
626 }
627
628 #else
629
630 /* non-rcu version */
631 static
632 void right_rotate(struct rcu_rbtree *rbtree,
633 struct rcu_rbtree_node *x)
634 {
635 struct rcu_rbtree_node *y;
636
637 lock_test_mutex();
638 y = x->_left;
639 x->_left = y->_right;
640 if (!rcu_rbtree_is_nil(rbtree, y->_right))
641 set_parent(y->_right, x, IS_LEFT);
642 set_parent(y, get_parent(x), get_pos(x));
643 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
644 rbtree->root = y;
645 else if (x == get_parent(x)->_right) {
646 get_parent(x)->_right = y;
647 } else {
648 get_parent(x)->_left = y;
649 }
650 y->_right = x;
651 set_parent(x, y, IS_RIGHT);
652 unlock_test_mutex();
653 }
654
655 #endif
656
657 static void rcu_rbtree_insert_fixup(struct rcu_rbtree *rbtree,
658 struct rcu_rbtree_node *z)
659 {
660 struct rcu_rbtree_node *y;
661
662 dbg_printf("insert fixup %p\n", z->begin);
663 assert(!is_decay(rbtree->root));
664
665 while (get_parent(z)->color == COLOR_RED) {
666 if (get_parent(z) == get_parent(get_parent(z))->_left) {
667 y = get_parent(get_parent(z))->_right;
668 if (y->color == COLOR_RED) {
669 get_parent(z)->color = COLOR_BLACK;
670 y->color = COLOR_BLACK;
671 get_parent(get_parent(z))->color = COLOR_RED;
672 z = get_parent(get_parent(z));
673 } else {
674 if (z == get_parent(z)->_right) {
675 z = get_parent(z);
676 left_rotate(rbtree, z);
677 z = get_decay(z);
678 assert(!is_decay(rbtree->root));
679 }
680 get_parent(z)->color = COLOR_BLACK;
681 get_parent(get_parent(z))->color = COLOR_RED;
682 assert(!is_decay(z));
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)));
686 assert(!is_decay(z));
687 assert(!is_decay(rbtree->root));
688 }
689 } else {
690 y = get_parent(get_parent(z))->_left;
691 if (y->color == COLOR_RED) {
692 get_parent(z)->color = COLOR_BLACK;
693 y->color = COLOR_BLACK;
694 get_parent(get_parent(z))->color = COLOR_RED;
695 z = get_parent(get_parent(z));
696 } else {
697 if (z == get_parent(z)->_left) {
698 z = get_parent(z);
699 right_rotate(rbtree, z);
700 z = get_decay(z);
701 assert(!is_decay(rbtree->root));
702 }
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)));
706 assert(!is_decay(z));
707 assert(!is_decay(rbtree->root));
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 */
719 int rcu_rbtree_insert(struct rcu_rbtree *rbtree,
720 struct rcu_rbtree_node *z)
721 {
722 struct rcu_rbtree_node *x, *y;
723
724 dbg_printf("insert %p\n", z->begin);
725 assert(!is_decay(rbtree->root));
726
727 y = make_nil(rbtree);
728 x = rbtree->root;
729 while (!rcu_rbtree_is_nil(rbtree, x)) {
730 y = x;
731 if (rbtree->comp(z->begin, x->begin) < 0)
732 x = x->_left;
733 else
734 x = x->_right;
735 }
736
737 z->_left = make_nil(rbtree);
738 z->_right = make_nil(rbtree);
739 z->color = COLOR_RED;
740 z->decay_next = NULL;
741 z->max_end = z->end;
742
743 if (rcu_rbtree_is_nil(rbtree, y)) {
744 set_parent(z, y, IS_RIGHT); /* pos arbitrary for root node */
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();
750 _CMM_STORE_SHARED(rbtree->root, z);
751 } else if (rbtree->comp(z->begin, y->begin) < 0) {
752 y = dup_decay_node(rbtree, y);
753 set_parent(z, y, IS_LEFT);
754 if (get_pos(z) == IS_LEFT)
755 _CMM_STORE_SHARED(y->_left, z);
756 else
757 _CMM_STORE_SHARED(y->_right, z);
758 populate_node_end(rbtree, y, 1, NULL);
759 } else {
760 y = dup_decay_node(rbtree, y);
761 set_parent(z, y, IS_RIGHT);
762 if (get_pos(z) == IS_LEFT)
763 _CMM_STORE_SHARED(y->_left, z);
764 else
765 _CMM_STORE_SHARED(y->_right, z);
766 populate_node_end(rbtree, y, 1, NULL);
767 }
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.
780 */
781
782 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
783
784 static
785 void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
786 struct rcu_rbtree_node *u,
787 struct rcu_rbtree_node *v,
788 unsigned int copy_parents,
789 struct rcu_rbtree_node *stop)
790 {
791 dbg_printf("transplant %p\n", v->begin);
792
793 if (!rcu_rbtree_is_nil(rbtree, v))
794 v = dup_decay_node(rbtree, v);
795
796 if (rcu_rbtree_is_nil(rbtree, get_parent(u))) {
797 /* pos is arbitrary for root node */
798 set_parent(v, get_parent(u), IS_RIGHT);
799 cmm_smp_wmb(); /* write into node before publish */
800 _CMM_STORE_SHARED(rbtree->root, v);
801 } else {
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);
810 else
811 _CMM_STORE_SHARED(vp->_right, v);
812 populate_node_end(rbtree, vp, copy_parents, stop);
813 }
814
815 /* Point children to new copy (parent only used by updates/next/prev) */
816 if (!rcu_rbtree_is_nil(rbtree, v)) {
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));
821 }
822 assert(!is_decay(rbtree->root));
823 }
824
825 #else
826
827 /* Non-RCU version */
828 static
829 void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
830 struct rcu_rbtree_node *u,
831 struct rcu_rbtree_node *v,
832 unsigned int copy_parents,
833 struct rcu_rbtree_node *stop)
834 {
835 dbg_printf("transplant %p\n", v->begin);
836
837 lock_test_mutex();
838 if (rcu_rbtree_is_nil(rbtree, get_parent(u)))
839 rbtree->root = v;
840 else if (u == get_parent(u)->_left)
841 get_parent(u)->_left = v;
842 else
843 get_parent(u)->_right = v;
844 set_parent(v, get_parent(u), get_pos(u));
845 unlock_test_mutex();
846 }
847
848 #endif
849
850 static void rcu_rbtree_remove_fixup(struct rcu_rbtree *rbtree,
851 struct rcu_rbtree_node *x)
852 {
853 dbg_printf("remove fixup %p\n", x->begin);
854
855 while (x != rbtree->root && x->color == COLOR_BLACK) {
856 assert(!is_decay(get_parent(x)));
857 assert(!is_decay(get_parent(x)->_left));
858 if (x == get_parent(x)->_left) {
859 struct rcu_rbtree_node *w;
860
861 w = get_parent(x)->_right;
862
863 if (w->color == COLOR_RED) {
864 w->color = COLOR_BLACK;
865 get_parent(x)->color = COLOR_RED;
866 left_rotate(rbtree, get_parent(x));
867 x = get_decay(x);
868 assert(!is_decay(rbtree->root));
869 w = get_parent(x)->_right;
870 }
871 if (w->_left->color == COLOR_BLACK
872 && w->_right->color == COLOR_BLACK) {
873 w->color = COLOR_RED;
874 x = get_parent(x);
875 assert(!is_decay(rbtree->root));
876 assert(!is_decay(x));
877 } else {
878 if (w->_right->color == COLOR_BLACK) {
879 w->_left->color = COLOR_BLACK;
880 w->color = COLOR_RED;
881 right_rotate(rbtree, w);
882 assert(!is_decay(rbtree->root));
883 x = get_decay(x);
884 w = get_parent(x)->_right;
885 }
886 w->color = get_parent(x)->color;
887 get_parent(x)->color = COLOR_BLACK;
888 w->_right->color = COLOR_BLACK;
889 left_rotate(rbtree, get_parent(x));
890 assert(!is_decay(rbtree->root));
891 x = rbtree->root;
892 }
893 } else {
894 struct rcu_rbtree_node *w;
895
896 w = get_parent(x)->_left;
897
898 if (w->color == COLOR_RED) {
899 w->color = COLOR_BLACK;
900 get_parent(x)->color = COLOR_RED;
901 right_rotate(rbtree, get_parent(x));
902 assert(!is_decay(rbtree->root));
903 x = get_decay(x);
904 w = get_parent(x)->_left;
905 }
906 if (w->_right->color == COLOR_BLACK
907 && w->_left->color == COLOR_BLACK) {
908 w->color = COLOR_RED;
909 x = get_parent(x);
910 assert(!is_decay(rbtree->root));
911 assert(!is_decay(x));
912 } else {
913 if (w->_left->color == COLOR_BLACK) {
914 w->_right->color = COLOR_BLACK;
915 w->color = COLOR_RED;
916 left_rotate(rbtree, w);
917 assert(!is_decay(rbtree->root));
918 x = get_decay(x);
919 w = get_parent(x)->_left;
920 }
921 w->color = get_parent(x)->color;
922 get_parent(x)->color = COLOR_BLACK;
923 w->_left->color = COLOR_BLACK;
924 right_rotate(rbtree, get_parent(x));
925 assert(!is_decay(rbtree->root));
926 x = rbtree->root;
927 }
928 }
929 }
930 x->color = COLOR_BLACK;
931 }
932
933 /*
934 * Delete z. All non-copied children left/right positions are unchanged.
935 */
936 static
937 void rcu_rbtree_remove_nonil(struct rcu_rbtree *rbtree,
938 struct rcu_rbtree_node *z,
939 struct rcu_rbtree_node *y)
940 {
941 struct rcu_rbtree_node *x;
942
943 dbg_printf("remove nonil %p\n", z->begin);
944 show_tree(rbtree);
945
946 assert(!is_decay(z));
947 assert(!is_decay(y));
948 assert(!is_decay(y->_right));
949 assert(!is_decay(get_parent(y)));
950 x = y->_right;
951 assert(!is_decay(x));
952 if (get_parent(y) == z) {
953 y = dup_decay_node(rbtree, y);
954 set_parent(x, y, get_pos(x)); /* parent for nil */
955 /* y is z's right node: set left will just update y */
956 set_left(rbtree, y, z->_left);
957 rcu_rbtree_transplant(rbtree, z, y, 1, NULL);
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 */
964 y = rcu_rbtree_min_dup_decay(rbtree, z->_right, &z_right);
965 assert(!is_decay(y));
966 assert(!is_decay(z));
967 oy_right = y->_right;
968
969 /*
970 * The max child begin of z_right does not change, because
971 * we're only changing its left children.
972 */
973 y->_right = z_right;
974 set_parent(y->_right, y, IS_RIGHT);
975 assert(!is_decay(z->_left));
976 y->_left = z->_left;
977 assert(!is_decay(oy_right));
978 /*
979 * Transplant of oy_right to old y's location will only
980 * trigger a "end" value update of the already copied branch
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 */
986 rcu_rbtree_transplant(rbtree, y, oy_right, 0, y);
987 rcu_rbtree_transplant(rbtree, z, y, 1, NULL);
988 /* Update children */
989 (void) rcu_rbtree_min_update_decay(rbtree, y->_right);
990 }
991 y = get_decay(y);
992 assert(!is_decay(z));
993 assert(!is_decay(z->_left));
994 y->color = z->color;
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));
999 }
1000
1001 int 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
1007 assert(!is_decay(rbtree->root));
1008 dbg_printf("remove %p\n", z->begin);
1009 show_tree(rbtree);
1010
1011 assert(!is_decay(z));
1012 y = z;
1013 y_original_color = y->color;
1014
1015 if (rcu_rbtree_is_nil(rbtree, z->_left)) {
1016 rcu_rbtree_transplant(rbtree, z, z->_right, 1, NULL);
1017 assert(!is_decay(z));
1018 x = get_decay(z->_right);
1019 show_tree(rbtree);
1020 } else if (rcu_rbtree_is_nil(rbtree, z->_right)) {
1021 rcu_rbtree_transplant(rbtree, z, z->_left, 1, NULL);
1022 assert(!is_decay(z));
1023 x = get_decay(z->_left);
1024 show_tree(rbtree);
1025 } else {
1026 y = rcu_rbtree_min(rbtree, z->_right);
1027 assert(!is_decay(y));
1028 y_original_color = y->color;
1029 x = y->_right;
1030 rcu_rbtree_remove_nonil(rbtree, z, y);
1031 x = get_decay(x);
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.06602 seconds and 5 git commands to generate.