Use comparison function for end/max_end
[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 if (rbtree->comp(max_end, node->_right->max_end) < 0)
386 max_end = node->_right->max_end;
387 }
388 if (!rcu_rbtree_is_nil(rbtree, node->_left)) {
389 if (rbtree->comp(max_end, node->_left->max_end) < 0)
390 max_end = node->_left->max_end;
391 }
392
393 if (rbtree->comp(max_end, node->max_end) != 0) {
394 if (prev && copy_parents) {
395 node = dup_decay_node(rbtree, node);
396 if (get_pos(prev) == IS_RIGHT)
397 node->_right = prev;
398 else
399 node->_left = prev;
400 set_parent(prev, node, get_pos(prev));
401 }
402 node->max_end = max_end;
403 } else {
404 /*
405 * We did not have to change the current node,
406 * so set the pointer to the prev node. If prev
407 * was null, this means we are coming in the
408 * first loop, and must update the parent of the
409 * node received as parameter (node).
410 */
411 if (prev)
412 node = prev;
413 top = get_parent(node);
414 cmm_smp_wmb(); /* write into node before publish */
415 /* make new branch visible to readers */
416 if (rcu_rbtree_is_nil(rbtree, top))
417 _CMM_STORE_SHARED(rbtree->root, node);
418 if (get_pos(node) == IS_LEFT)
419 _CMM_STORE_SHARED(top->_left, node);
420 else
421 _CMM_STORE_SHARED(top->_right, node);
422 goto end;
423 }
424
425 /* Check for propagation stop */
426 if (node == stop)
427 return;
428
429 prev = node;
430 node = get_parent(node);
431 } while (!rcu_rbtree_is_nil(rbtree, node));
432
433 top = node; /* nil */
434 cmm_smp_wmb(); /* write into node before publish */
435 /* make new branch visible to readers */
436 _CMM_STORE_SHARED(rbtree->root, prev);
437
438 end:
439 if (!copy_parents)
440 return;
441 /* update children */
442 node = orig_node;
443 do {
444 assert(!rcu_rbtree_is_nil(rbtree, node));
445 set_parent(node->_left, get_decay(get_parent(node->_left)), IS_LEFT);
446 set_parent(node->_right, get_decay(get_parent(node->_right)), IS_RIGHT);
447 } while ((node = get_parent(node)) != top);
448 }
449
450 /*
451 * We have to ensure these assumptions are correct for prev/next
452 * traversal:
453 *
454 * with x being a right child, the assumption that:
455 * get_parent(x)->_right == x
456 * or if x is a left child, the assumption that:
457 * get_parent(x)->_left == x
458 *
459 * This explains why we have to allocate a vc copy of the node for left_rotate,
460 * right_rotate and transplant operations.
461 *
462 * We always ensure that the right/left child and correct parent is set in the
463 * node copies *before* we reparent the children and make the upper-level point
464 * to the copy.
465 */
466
467 /* RCU: copy x and y, atomically point to new versions. GC old. */
468 /* Should be eventually followed by a cmm_smp_wmc() */
469
470 #ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
471
472 static
473 void left_rotate(struct rcu_rbtree *rbtree,
474 struct rcu_rbtree_node *x)
475 {
476 struct rcu_rbtree_node *y, *y_left;
477
478 y = x->_right;
479 y_left = y->_left;
480
481 /* Now operate on new copy, decay old versions */
482 x = dup_decay_node(rbtree, x);
483 y = dup_decay_node(rbtree, y);
484 y_left = dup_decay_node(rbtree, y_left);
485
486 /* Internal node modifications */
487 set_parent(y, get_parent(x), get_pos(x));
488 set_parent(x, y, IS_LEFT);
489 set_left(rbtree, y, x);
490 set_right(rbtree, x, y_left);
491
492 if (!rcu_rbtree_is_nil(rbtree, y_left))
493 set_parent(y_left, x, IS_RIGHT);
494
495 cmm_smp_wmb(); /* write into node before publish */
496
497 /* External references update (visible by readers) */
498 if (rcu_rbtree_is_nil(rbtree, get_parent(y)))
499 _CMM_STORE_SHARED(rbtree->root, y);
500 else if (get_pos(y) == IS_LEFT)
501 _CMM_STORE_SHARED(get_parent(y)->_left, y);
502 else
503 _CMM_STORE_SHARED(get_parent(y)->_right, y);
504
505 /* Point children to new copy (parent only used by updates/next/prev) */
506 set_parent(x->_left, get_decay(get_parent(x->_left)),
507 get_pos(x->_left));
508 set_parent(y->_right, get_decay(get_parent(y->_right)),
509 get_pos(y->_right));
510 if (!rcu_rbtree_is_nil(rbtree, y_left)) {
511 set_parent(y_left->_right,
512 get_decay(get_parent(y_left->_right)),
513 get_pos(y_left->_right));
514 set_parent(y_left->_left,
515 get_decay(get_parent(y_left->_left)),
516 get_pos(y_left->_left));
517 }
518
519 /* Sanity checks */
520 assert(y == rbtree->root || get_parent(y)->_left == y
521 || get_parent(y)->_right == y);
522 assert(x == rbtree->root || get_parent(x)->_left == x
523 || get_parent(x)->_right == x);
524 assert(rcu_rbtree_is_nil(rbtree, x->_right) || get_parent(x->_right) == x);
525 assert(rcu_rbtree_is_nil(rbtree, x->_left) || get_parent(x->_left) == x);
526 assert(rcu_rbtree_is_nil(rbtree, y->_right) || get_parent(y->_right) == y);
527 assert(rcu_rbtree_is_nil(rbtree, y->_left) || get_parent(y->_left) == y);
528 assert(!is_decay(rbtree->root));
529 assert(!is_decay(x));
530 assert(!is_decay(y));
531 assert(!is_decay(x->_right));
532 assert(!is_decay(x->_left));
533 assert(!is_decay(y->_right));
534 assert(!is_decay(y->_left));
535 }
536
537 #else
538
539 /* non-rcu version */
540 static
541 void left_rotate(struct rcu_rbtree *rbtree,
542 struct rcu_rbtree_node *x)
543 {
544 struct rcu_rbtree_node *y;
545
546 lock_test_mutex();
547 y = x->_right;
548 x->_right = y->_left;
549 if (!rcu_rbtree_is_nil(rbtree, y->_left))
550 set_parent(y->_left, x, IS_RIGHT);
551 set_parent(y, get_parent(x), get_pos(x));
552 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
553 rbtree->root = y;
554 else if (x == get_parent(x)->_left) {
555 get_parent(x)->_left = y;
556 } else {
557 get_parent(x)->_right = y;
558 }
559 y->_left = x;
560 set_parent(x, y, IS_LEFT);
561 unlock_test_mutex();
562 }
563
564 #endif
565
566 #ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
567 static
568 void right_rotate(struct rcu_rbtree *rbtree,
569 struct rcu_rbtree_node *x)
570 {
571 struct rcu_rbtree_node *y, *y_right;
572
573 y = x->_left;
574 y_right = y->_right;
575
576 /* Now operate on new copy, decay old versions */
577 x = dup_decay_node(rbtree, x);
578 y = dup_decay_node(rbtree, y);
579 y_right = dup_decay_node(rbtree, y_right);
580
581 /* Internal node modifications */
582 set_parent(y, get_parent(x), get_pos(x));
583 set_parent(x, y, IS_RIGHT);
584 set_right(rbtree, y, x);
585 set_left(rbtree, x, y_right);
586
587 if (!rcu_rbtree_is_nil(rbtree, y_right))
588 set_parent(y_right, x, IS_LEFT);
589
590 cmm_smp_wmb(); /* write into node before publish */
591
592 /* External references update (visible by readers) */
593 if (rcu_rbtree_is_nil(rbtree, get_parent(y)))
594 _CMM_STORE_SHARED(rbtree->root, y);
595 else if (get_pos(y) == IS_RIGHT)
596 _CMM_STORE_SHARED(get_parent(y)->_right, y);
597 else
598 _CMM_STORE_SHARED(get_parent(y)->_left, y);
599
600 /* Point children to new copy (parent only used by updates/next/prev) */
601 set_parent(x->_right, get_decay(get_parent(x->_right)),
602 get_pos(x->_right));
603 set_parent(y->_left, get_decay(get_parent(y->_left)),
604 get_pos(y->_left));
605 if (!rcu_rbtree_is_nil(rbtree, y_right)) {
606 set_parent(y_right->_left,
607 get_decay(get_parent(y_right->_left)),
608 get_pos(y_right->_left));
609 set_parent(y_right->_right,
610 get_decay(get_parent(y_right->_right)),
611 get_pos(y_right->_right));
612 }
613
614 /* Sanity checks */
615 assert(y == rbtree->root || get_parent(y)->_right == y
616 || get_parent(y)->_left == y);
617 assert(x == rbtree->root || get_parent(x)->_right == x
618 || get_parent(x)->_left == x);
619 assert(rcu_rbtree_is_nil(rbtree, x->_left) || get_parent(x->_left) == x);
620 assert(rcu_rbtree_is_nil(rbtree, x->_right) || get_parent(x->_right) == x);
621 assert(rcu_rbtree_is_nil(rbtree, y->_left) || get_parent(y->_left) == y);
622 assert(rcu_rbtree_is_nil(rbtree, y->_right) || get_parent(y->_right) == y);
623 assert(!is_decay(rbtree->root));
624 assert(!is_decay(x));
625 assert(!is_decay(y));
626 assert(!is_decay(x->_left));
627 assert(!is_decay(x->_right));
628 assert(!is_decay(y->_left));
629 assert(!is_decay(y->_right));
630 }
631
632 #else
633
634 /* non-rcu version */
635 static
636 void right_rotate(struct rcu_rbtree *rbtree,
637 struct rcu_rbtree_node *x)
638 {
639 struct rcu_rbtree_node *y;
640
641 lock_test_mutex();
642 y = x->_left;
643 x->_left = y->_right;
644 if (!rcu_rbtree_is_nil(rbtree, y->_right))
645 set_parent(y->_right, x, IS_LEFT);
646 set_parent(y, get_parent(x), get_pos(x));
647 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
648 rbtree->root = y;
649 else if (x == get_parent(x)->_right) {
650 get_parent(x)->_right = y;
651 } else {
652 get_parent(x)->_left = y;
653 }
654 y->_right = x;
655 set_parent(x, y, IS_RIGHT);
656 unlock_test_mutex();
657 }
658
659 #endif
660
661 static void rcu_rbtree_insert_fixup(struct rcu_rbtree *rbtree,
662 struct rcu_rbtree_node *z)
663 {
664 struct rcu_rbtree_node *y;
665
666 dbg_printf("insert fixup %p\n", z->begin);
667 assert(!is_decay(rbtree->root));
668
669 while (get_parent(z)->color == COLOR_RED) {
670 if (get_parent(z) == get_parent(get_parent(z))->_left) {
671 y = get_parent(get_parent(z))->_right;
672 if (y->color == COLOR_RED) {
673 get_parent(z)->color = COLOR_BLACK;
674 y->color = COLOR_BLACK;
675 get_parent(get_parent(z))->color = COLOR_RED;
676 z = get_parent(get_parent(z));
677 } else {
678 if (z == get_parent(z)->_right) {
679 z = get_parent(z);
680 left_rotate(rbtree, z);
681 z = get_decay(z);
682 assert(!is_decay(rbtree->root));
683 }
684 get_parent(z)->color = COLOR_BLACK;
685 get_parent(get_parent(z))->color = COLOR_RED;
686 assert(!is_decay(z));
687 assert(!is_decay(get_parent(z)));
688 assert(!is_decay(get_parent(get_parent(z))));
689 right_rotate(rbtree, get_parent(get_parent(z)));
690 assert(!is_decay(z));
691 assert(!is_decay(rbtree->root));
692 }
693 } else {
694 y = get_parent(get_parent(z))->_left;
695 if (y->color == COLOR_RED) {
696 get_parent(z)->color = COLOR_BLACK;
697 y->color = COLOR_BLACK;
698 get_parent(get_parent(z))->color = COLOR_RED;
699 z = get_parent(get_parent(z));
700 } else {
701 if (z == get_parent(z)->_left) {
702 z = get_parent(z);
703 right_rotate(rbtree, z);
704 z = get_decay(z);
705 assert(!is_decay(rbtree->root));
706 }
707 get_parent(z)->color = COLOR_BLACK;
708 get_parent(get_parent(z))->color = COLOR_RED;
709 left_rotate(rbtree, get_parent(get_parent(z)));
710 assert(!is_decay(z));
711 assert(!is_decay(rbtree->root));
712 }
713 }
714 }
715 rbtree->root->color = COLOR_BLACK;
716 }
717
718 /*
719 * rcu_rbtree_insert - Insert a node in the RCU rbtree
720 *
721 * Returns 0 on success, or < 0 on error.
722 */
723 int rcu_rbtree_insert(struct rcu_rbtree *rbtree,
724 struct rcu_rbtree_node *z)
725 {
726 struct rcu_rbtree_node *x, *y;
727
728 dbg_printf("insert %p\n", z->begin);
729 assert(!is_decay(rbtree->root));
730
731 y = make_nil(rbtree);
732 x = rbtree->root;
733 while (!rcu_rbtree_is_nil(rbtree, x)) {
734 y = x;
735 if (rbtree->comp(z->begin, x->begin) < 0)
736 x = x->_left;
737 else
738 x = x->_right;
739 }
740
741 z->_left = make_nil(rbtree);
742 z->_right = make_nil(rbtree);
743 z->color = COLOR_RED;
744 z->decay_next = NULL;
745 z->max_end = z->end;
746
747 if (rcu_rbtree_is_nil(rbtree, y)) {
748 set_parent(z, y, IS_RIGHT); /* pos arbitrary for root node */
749 /*
750 * Order stores to z (children/parents) before stores
751 * that will make it visible to the rest of the tree.
752 */
753 cmm_smp_wmb();
754 _CMM_STORE_SHARED(rbtree->root, z);
755 } else if (rbtree->comp(z->begin, y->begin) < 0) {
756 y = dup_decay_node(rbtree, y);
757 set_parent(z, y, IS_LEFT);
758 if (get_pos(z) == IS_LEFT)
759 _CMM_STORE_SHARED(y->_left, z);
760 else
761 _CMM_STORE_SHARED(y->_right, z);
762 populate_node_end(rbtree, y, 1, NULL);
763 } else {
764 y = dup_decay_node(rbtree, y);
765 set_parent(z, y, IS_RIGHT);
766 if (get_pos(z) == IS_LEFT)
767 _CMM_STORE_SHARED(y->_left, z);
768 else
769 _CMM_STORE_SHARED(y->_right, z);
770 populate_node_end(rbtree, y, 1, NULL);
771 }
772 rcu_rbtree_insert_fixup(rbtree, z);
773 /*
774 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
775 */
776 cmm_smp_wmc();
777 show_tree(rbtree);
778
779 return 0;
780 }
781
782 /*
783 * Transplant v into u position.
784 */
785
786 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
787
788 static
789 void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
790 struct rcu_rbtree_node *u,
791 struct rcu_rbtree_node *v,
792 unsigned int copy_parents,
793 struct rcu_rbtree_node *stop)
794 {
795 dbg_printf("transplant %p\n", v->begin);
796
797 if (!rcu_rbtree_is_nil(rbtree, v))
798 v = dup_decay_node(rbtree, v);
799
800 if (rcu_rbtree_is_nil(rbtree, get_parent(u))) {
801 /* pos is arbitrary for root node */
802 set_parent(v, get_parent(u), IS_RIGHT);
803 cmm_smp_wmb(); /* write into node before publish */
804 _CMM_STORE_SHARED(rbtree->root, v);
805 } else {
806 struct rcu_rbtree_node *vp;
807
808 vp = get_parent(u);
809 if (copy_parents)
810 vp = dup_decay_node(rbtree, vp);
811 set_parent(v, vp, get_pos(u));
812 if (get_pos(v) == IS_LEFT)
813 _CMM_STORE_SHARED(vp->_left, v);
814 else
815 _CMM_STORE_SHARED(vp->_right, v);
816 populate_node_end(rbtree, vp, copy_parents, stop);
817 }
818
819 /* Point children to new copy (parent only used by updates/next/prev) */
820 if (!rcu_rbtree_is_nil(rbtree, v)) {
821 set_parent(v->_right, get_decay(get_parent(v->_right)),
822 get_pos(v->_right));
823 set_parent(v->_left, get_decay(get_parent(v->_left)),
824 get_pos(v->_left));
825 }
826 assert(!is_decay(rbtree->root));
827 }
828
829 #else
830
831 /* Non-RCU version */
832 static
833 void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
834 struct rcu_rbtree_node *u,
835 struct rcu_rbtree_node *v,
836 unsigned int copy_parents,
837 struct rcu_rbtree_node *stop)
838 {
839 dbg_printf("transplant %p\n", v->begin);
840
841 lock_test_mutex();
842 if (rcu_rbtree_is_nil(rbtree, get_parent(u)))
843 rbtree->root = v;
844 else if (u == get_parent(u)->_left)
845 get_parent(u)->_left = v;
846 else
847 get_parent(u)->_right = v;
848 set_parent(v, get_parent(u), get_pos(u));
849 unlock_test_mutex();
850 }
851
852 #endif
853
854 static void rcu_rbtree_remove_fixup(struct rcu_rbtree *rbtree,
855 struct rcu_rbtree_node *x)
856 {
857 dbg_printf("remove fixup %p\n", x->begin);
858
859 while (x != rbtree->root && x->color == COLOR_BLACK) {
860 assert(!is_decay(get_parent(x)));
861 assert(!is_decay(get_parent(x)->_left));
862 if (x == get_parent(x)->_left) {
863 struct rcu_rbtree_node *w;
864
865 w = get_parent(x)->_right;
866
867 if (w->color == COLOR_RED) {
868 w->color = COLOR_BLACK;
869 get_parent(x)->color = COLOR_RED;
870 left_rotate(rbtree, get_parent(x));
871 x = get_decay(x);
872 assert(!is_decay(rbtree->root));
873 w = get_parent(x)->_right;
874 }
875 if (w->_left->color == COLOR_BLACK
876 && w->_right->color == COLOR_BLACK) {
877 w->color = COLOR_RED;
878 x = get_parent(x);
879 assert(!is_decay(rbtree->root));
880 assert(!is_decay(x));
881 } else {
882 if (w->_right->color == COLOR_BLACK) {
883 w->_left->color = COLOR_BLACK;
884 w->color = COLOR_RED;
885 right_rotate(rbtree, w);
886 assert(!is_decay(rbtree->root));
887 x = get_decay(x);
888 w = get_parent(x)->_right;
889 }
890 w->color = get_parent(x)->color;
891 get_parent(x)->color = COLOR_BLACK;
892 w->_right->color = COLOR_BLACK;
893 left_rotate(rbtree, get_parent(x));
894 assert(!is_decay(rbtree->root));
895 x = rbtree->root;
896 }
897 } else {
898 struct rcu_rbtree_node *w;
899
900 w = get_parent(x)->_left;
901
902 if (w->color == COLOR_RED) {
903 w->color = COLOR_BLACK;
904 get_parent(x)->color = COLOR_RED;
905 right_rotate(rbtree, get_parent(x));
906 assert(!is_decay(rbtree->root));
907 x = get_decay(x);
908 w = get_parent(x)->_left;
909 }
910 if (w->_right->color == COLOR_BLACK
911 && w->_left->color == COLOR_BLACK) {
912 w->color = COLOR_RED;
913 x = get_parent(x);
914 assert(!is_decay(rbtree->root));
915 assert(!is_decay(x));
916 } else {
917 if (w->_left->color == COLOR_BLACK) {
918 w->_right->color = COLOR_BLACK;
919 w->color = COLOR_RED;
920 left_rotate(rbtree, w);
921 assert(!is_decay(rbtree->root));
922 x = get_decay(x);
923 w = get_parent(x)->_left;
924 }
925 w->color = get_parent(x)->color;
926 get_parent(x)->color = COLOR_BLACK;
927 w->_left->color = COLOR_BLACK;
928 right_rotate(rbtree, get_parent(x));
929 assert(!is_decay(rbtree->root));
930 x = rbtree->root;
931 }
932 }
933 }
934 x->color = COLOR_BLACK;
935 }
936
937 /*
938 * Delete z. All non-copied children left/right positions are unchanged.
939 */
940 static
941 void rcu_rbtree_remove_nonil(struct rcu_rbtree *rbtree,
942 struct rcu_rbtree_node *z,
943 struct rcu_rbtree_node *y)
944 {
945 struct rcu_rbtree_node *x;
946
947 dbg_printf("remove nonil %p\n", z->begin);
948 show_tree(rbtree);
949
950 assert(!is_decay(z));
951 assert(!is_decay(y));
952 assert(!is_decay(y->_right));
953 assert(!is_decay(get_parent(y)));
954 x = y->_right;
955 assert(!is_decay(x));
956 if (get_parent(y) == z) {
957 y = dup_decay_node(rbtree, y);
958 set_parent(x, y, get_pos(x)); /* parent for nil */
959 /* y is z's right node: set left will just update y */
960 set_left(rbtree, y, z->_left);
961 rcu_rbtree_transplant(rbtree, z, y, 1, NULL);
962 } else {
963 struct rcu_rbtree_node *oy_right, *z_right;
964
965 /*
966 * Need to make sure y is always visible by readers.
967 */
968 y = rcu_rbtree_min_dup_decay(rbtree, z->_right, &z_right);
969 assert(!is_decay(y));
970 assert(!is_decay(z));
971 oy_right = y->_right;
972
973 /*
974 * The max child begin of z_right does not change, because
975 * we're only changing its left children.
976 */
977 y->_right = z_right;
978 set_parent(y->_right, y, IS_RIGHT);
979 assert(!is_decay(z->_left));
980 y->_left = z->_left;
981 assert(!is_decay(oy_right));
982 /*
983 * Transplant of oy_right to old y's location will only
984 * trigger a "end" value update of the already copied branch
985 * (which is not visible yet). We are transplanting
986 * oy_right as a left child of old y's parent, so the
987 * min values update propagated upward necessarily stops
988 * at z_right.
989 */
990 rcu_rbtree_transplant(rbtree, y, oy_right, 0, y);
991 rcu_rbtree_transplant(rbtree, z, y, 1, NULL);
992 /* Update children */
993 (void) rcu_rbtree_min_update_decay(rbtree, y->_right);
994 }
995 y = get_decay(y);
996 assert(!is_decay(z));
997 assert(!is_decay(z->_left));
998 y->color = z->color;
999 set_parent(y->_left, y, IS_LEFT);
1000 set_parent(y->_right, get_decay(get_parent(y->_right)), IS_RIGHT);
1001 assert(!is_decay(y->_left));
1002 assert(!is_decay(y->_right));
1003 }
1004
1005 int rcu_rbtree_remove(struct rcu_rbtree *rbtree,
1006 struct rcu_rbtree_node *z)
1007 {
1008 struct rcu_rbtree_node *x, *y;
1009 unsigned int y_original_color;
1010
1011 assert(!is_decay(rbtree->root));
1012 dbg_printf("remove %p\n", z->begin);
1013 show_tree(rbtree);
1014
1015 assert(!is_decay(z));
1016 y = z;
1017 y_original_color = y->color;
1018
1019 if (rcu_rbtree_is_nil(rbtree, z->_left)) {
1020 rcu_rbtree_transplant(rbtree, z, z->_right, 1, NULL);
1021 assert(!is_decay(z));
1022 x = get_decay(z->_right);
1023 show_tree(rbtree);
1024 } else if (rcu_rbtree_is_nil(rbtree, z->_right)) {
1025 rcu_rbtree_transplant(rbtree, z, z->_left, 1, NULL);
1026 assert(!is_decay(z));
1027 x = get_decay(z->_left);
1028 show_tree(rbtree);
1029 } else {
1030 y = rcu_rbtree_min(rbtree, z->_right);
1031 assert(!is_decay(y));
1032 y_original_color = y->color;
1033 x = y->_right;
1034 rcu_rbtree_remove_nonil(rbtree, z, y);
1035 x = get_decay(x);
1036 show_tree(rbtree);
1037 }
1038 if (y_original_color == COLOR_BLACK)
1039 rcu_rbtree_remove_fixup(rbtree, x);
1040 show_tree(rbtree);
1041 /*
1042 * Commit all _CMM_STORE_SHARED().
1043 */
1044 cmm_smp_wmc();
1045
1046 return 0;
1047 }
This page took 0.068466 seconds and 5 git commands to generate.