Rename node fields to begin/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 pe: %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) get_parent(node)->end,
201 (unsigned long) node->_right->key,
202 (unsigned long) node->_left->key,
203 node->color ? "red" : "black",
204 get_pos(node) ? "right" : "left",
205 rcu_rbtree_is_nil(rbtree, node) ? "nil" : "");
206 node = rcu_rbtree_next(rbtree, node);
207 }
208 printf("\n");
209 }
210 #else /* DEBUG */
211 static
212 void show_tree(struct rcu_rbtree *rbtree)
213 {
214 }
215 #endif /* DEBUG */
216
217 static
218 struct rcu_rbtree_node *make_nil(struct rcu_rbtree *rbtree)
219 {
220 return &rbtree->nil_node;
221 }
222
223 /*
224 * Iterative rbtree search.
225 */
226 struct rcu_rbtree_node *rcu_rbtree_search(struct rcu_rbtree *rbtree,
227 struct rcu_rbtree_node *x,
228 void *k)
229 {
230 x = rcu_dereference(x);
231 int comp;
232
233 while (!rcu_rbtree_is_nil(rbtree, x) && (comp = rbtree->comp(k, x->begin)) != 0) {
234 dbg_usleep(10);
235 if (comp < 0)
236 x = rcu_dereference(x->_left);
237 else
238 x = rcu_dereference(x->_right);
239 }
240 return x;
241 }
242
243 static
244 struct rcu_rbtree_node *rcu_rbtree_min_dup_decay(struct rcu_rbtree *rbtree,
245 struct rcu_rbtree_node *x,
246 struct rcu_rbtree_node **zr)
247 {
248 struct rcu_rbtree_node *xl;
249
250 x = rcu_dereference(x);
251
252 if (rcu_rbtree_is_nil(rbtree, x)) {
253 *zr = x;
254 return x;
255 } else
256 *zr = x = dup_decay_node(rbtree, x);
257
258 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left))) {
259 x = dup_decay_node(rbtree, xl);
260 set_parent(x, get_decay(get_parent(x)), get_pos(x));
261 get_parent(x)->_left = get_decay(get_parent(x)->_left);
262 }
263 return x;
264 }
265
266 static
267 struct rcu_rbtree_node *rcu_rbtree_min_update_decay(struct rcu_rbtree *rbtree,
268 struct rcu_rbtree_node *x)
269 {
270 struct rcu_rbtree_node *xl;
271
272 x = rcu_dereference(x);
273
274 if (rcu_rbtree_is_nil(rbtree, x))
275 return x;
276 else {
277 set_parent(x->_right, get_decay(get_parent(x->_right)),
278 get_pos(x->_right));
279 set_parent(x->_left, get_decay(get_parent(x->_left)),
280 get_pos(x->_left));
281 }
282
283 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left))) {
284 x = xl;
285 set_parent(x->_right, get_decay(get_parent(x->_right)),
286 get_pos(x->_right));
287 set_parent(x->_left, get_decay(get_parent(x->_left)),
288 get_pos(x->_left));
289 }
290 return x;
291 }
292
293 struct rcu_rbtree_node *rcu_rbtree_min(struct rcu_rbtree *rbtree,
294 struct rcu_rbtree_node *x)
295 {
296 struct rcu_rbtree_node *xl;
297
298 x = rcu_dereference(x);
299
300 if (rcu_rbtree_is_nil(rbtree, x))
301 return x;
302
303 while (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left)))
304 x = xl;
305 return x;
306 }
307
308 struct rcu_rbtree_node *rcu_rbtree_max(struct rcu_rbtree *rbtree,
309 struct rcu_rbtree_node *x)
310 {
311 struct rcu_rbtree_node *xr;
312
313 x = rcu_dereference(x);
314
315 if (rcu_rbtree_is_nil(rbtree, x))
316 return x;
317
318 while (!rcu_rbtree_is_nil(rbtree, xr = rcu_dereference(x->_right)))
319 x = xr;
320 return x;
321 }
322
323 /*
324 * FIXME:
325 * Updates should wait for a grace period between update of the
326 * redirect pointer and update of the parent child pointer. This is to make sure
327 * that no reference to the old entry exist.
328 */
329
330 /*
331 * RCU read lock must be held across the next/prev calls to ensure validity of
332 * the returned node.
333 */
334 struct rcu_rbtree_node *rcu_rbtree_next(struct rcu_rbtree *rbtree,
335 struct rcu_rbtree_node *x)
336 {
337 struct rcu_rbtree_node *xr, *y;
338 unsigned int x_pos;
339
340 x = rcu_dereference(x);
341
342 if (!rcu_rbtree_is_nil(rbtree, xr = rcu_dereference(x->_right)))
343 return rcu_rbtree_min(rbtree, xr);
344 y = get_parent_and_pos(x, &x_pos);
345 while (!rcu_rbtree_is_nil(rbtree, y) && x_pos == IS_RIGHT) {
346 x = y;
347 y = get_parent_and_pos(y, &x_pos);
348 }
349 return y;
350 }
351
352 struct rcu_rbtree_node *rcu_rbtree_prev(struct rcu_rbtree *rbtree,
353 struct rcu_rbtree_node *x)
354 {
355 struct rcu_rbtree_node *xl, *y;
356 unsigned int x_pos;
357
358 x = rcu_dereference(x);
359
360 if (!rcu_rbtree_is_nil(rbtree, xl = rcu_dereference(x->_left)))
361 return rcu_rbtree_max(rbtree, xl);
362 y = get_parent_and_pos(x, &x_pos);
363 while (!rcu_rbtree_is_nil(rbtree, y) && x_pos == IS_LEFT) {
364 x = y;
365 y = get_parent_and_pos(y, &x_pos);
366 }
367 return y;
368 }
369
370 /*
371 * We have to ensure these assumptions are correct for prev/next
372 * traversal:
373 *
374 * with x being a right child, the assumption that:
375 * get_parent(x)->_right == x
376 * or if x is a left child, the assumption that:
377 * get_parent(x)->_left == x
378 *
379 * This explains why we have to allocate a vc copy of the node for left_rotate,
380 * right_rotate and transplant operations.
381 *
382 * We always ensure that the right/left child and correct parent is set in the
383 * node copies *before* we reparent the children and make the upper-level point
384 * to the copy.
385 */
386
387 /* RCU: copy x and y, atomically point to new versions. GC old. */
388 /* Should be eventually followed by a cmm_smp_wmc() */
389
390 #ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
391
392 static
393 void left_rotate(struct rcu_rbtree *rbtree,
394 struct rcu_rbtree_node *x)
395 {
396 struct rcu_rbtree_node *y, *y_left;
397
398 y = x->_right;
399 y_left = y->_left;
400
401 /* Now operate on new copy, decay old versions */
402 x = dup_decay_node(rbtree, x);
403 y = dup_decay_node(rbtree, y);
404 y_left = dup_decay_node(rbtree, y_left);
405
406 /* Internal node modifications */
407 set_parent(y, get_parent(x), get_pos(x));
408 set_parent(x, y, IS_LEFT);
409 set_left(rbtree, y, x);
410 set_right(rbtree, x, y_left);
411
412 if (!rcu_rbtree_is_nil(rbtree, y_left))
413 set_parent(y_left, x, IS_RIGHT);
414
415 cmm_smp_wmb(); /* write into node before publish */
416
417 /* External references update (visible by readers) */
418 if (rcu_rbtree_is_nil(rbtree, get_parent(y)))
419 _CMM_STORE_SHARED(rbtree->root, y);
420 else if (get_pos(y) == IS_LEFT)
421 _CMM_STORE_SHARED(get_parent(y)->_left, y);
422 else
423 _CMM_STORE_SHARED(get_parent(y)->_right, y);
424
425 /* Point children to new copy (parent only used by updates/next/prev) */
426 set_parent(x->_left, get_decay(get_parent(x->_left)),
427 get_pos(x->_left));
428 set_parent(y->_right, get_decay(get_parent(y->_right)),
429 get_pos(y->_right));
430 if (!rcu_rbtree_is_nil(rbtree, y_left)) {
431 set_parent(y_left->_right,
432 get_decay(get_parent(y_left->_right)),
433 get_pos(y_left->_right));
434 set_parent(y_left->_left,
435 get_decay(get_parent(y_left->_left)),
436 get_pos(y_left->_left));
437 }
438
439 /* Sanity checks */
440 assert(y == rbtree->root || get_parent(y)->_left == y
441 || get_parent(y)->_right == y);
442 assert(x == rbtree->root || get_parent(x)->_left == x
443 || get_parent(x)->_right == x);
444 assert(rcu_rbtree_is_nil(rbtree, x->_right) || get_parent(x->_right) == x);
445 assert(rcu_rbtree_is_nil(rbtree, x->_left) || get_parent(x->_left) == x);
446 assert(rcu_rbtree_is_nil(rbtree, y->_right) || get_parent(y->_right) == y);
447 assert(rcu_rbtree_is_nil(rbtree, y->_left) || get_parent(y->_left) == y);
448 assert(!is_decay(rbtree->root));
449 assert(!is_decay(x));
450 assert(!is_decay(y));
451 assert(!is_decay(x->_right));
452 assert(!is_decay(x->_left));
453 assert(!is_decay(y->_right));
454 assert(!is_decay(y->_left));
455 }
456
457 #else
458
459 /* non-rcu version */
460 static
461 void left_rotate(struct rcu_rbtree *rbtree,
462 struct rcu_rbtree_node *x)
463 {
464 struct rcu_rbtree_node *y;
465
466 lock_test_mutex();
467 y = x->_right;
468 x->_right = y->_left;
469 if (!rcu_rbtree_is_nil(rbtree, y->_left))
470 set_parent(y->_left, x, IS_RIGHT);
471 set_parent(y, get_parent(x), get_pos(x));
472 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
473 rbtree->root = y;
474 else if (x == get_parent(x)->_left) {
475 get_parent(x)->_left = y;
476 } else {
477 get_parent(x)->_right = y;
478 }
479 y->_left = x;
480 set_parent(x, y, IS_LEFT);
481 unlock_test_mutex();
482 }
483
484 #endif
485
486 #ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
487 static
488 void right_rotate(struct rcu_rbtree *rbtree,
489 struct rcu_rbtree_node *x)
490 {
491 struct rcu_rbtree_node *y, *y_right;
492
493 y = x->_left;
494 y_right = y->_right;
495
496 /* Now operate on new copy, decay old versions */
497 x = dup_decay_node(rbtree, x);
498 y = dup_decay_node(rbtree, y);
499 y_right = dup_decay_node(rbtree, y_right);
500
501 /* Internal node modifications */
502 set_parent(y, get_parent(x), get_pos(x));
503 set_parent(x, y, IS_RIGHT);
504 set_right(rbtree, y, x);
505 set_left(rbtree, x, y_right);
506
507 if (!rcu_rbtree_is_nil(rbtree, y_right))
508 set_parent(y_right, x, IS_LEFT);
509
510 cmm_smp_wmb(); /* write into node before publish */
511
512 /* External references update (visible by readers) */
513 if (rcu_rbtree_is_nil(rbtree, get_parent(y)))
514 _CMM_STORE_SHARED(rbtree->root, y);
515 else if (get_pos(y) == IS_RIGHT)
516 _CMM_STORE_SHARED(get_parent(y)->_right, y);
517 else
518 _CMM_STORE_SHARED(get_parent(y)->_left, y);
519
520 /* Point children to new copy (parent only used by updates/next/prev) */
521 set_parent(x->_right, get_decay(get_parent(x->_right)),
522 get_pos(x->_right));
523 set_parent(y->_left, get_decay(get_parent(y->_left)),
524 get_pos(y->_left));
525 if (!rcu_rbtree_is_nil(rbtree, y_right)) {
526 set_parent(y_right->_left,
527 get_decay(get_parent(y_right->_left)),
528 get_pos(y_right->_left));
529 set_parent(y_right->_right,
530 get_decay(get_parent(y_right->_right)),
531 get_pos(y_right->_right));
532 }
533
534 /* Sanity checks */
535 assert(y == rbtree->root || get_parent(y)->_right == y
536 || get_parent(y)->_left == y);
537 assert(x == rbtree->root || get_parent(x)->_right == x
538 || get_parent(x)->_left == x);
539 assert(rcu_rbtree_is_nil(rbtree, x->_left) || get_parent(x->_left) == x);
540 assert(rcu_rbtree_is_nil(rbtree, x->_right) || get_parent(x->_right) == x);
541 assert(rcu_rbtree_is_nil(rbtree, y->_left) || get_parent(y->_left) == y);
542 assert(rcu_rbtree_is_nil(rbtree, y->_right) || get_parent(y->_right) == y);
543 assert(!is_decay(rbtree->root));
544 assert(!is_decay(x));
545 assert(!is_decay(y));
546 assert(!is_decay(x->_left));
547 assert(!is_decay(x->_right));
548 assert(!is_decay(y->_left));
549 assert(!is_decay(y->_right));
550 }
551
552 #else
553
554 /* non-rcu version */
555 static
556 void right_rotate(struct rcu_rbtree *rbtree,
557 struct rcu_rbtree_node *x)
558 {
559 struct rcu_rbtree_node *y;
560
561 lock_test_mutex();
562 y = x->_left;
563 x->_left = y->_right;
564 if (!rcu_rbtree_is_nil(rbtree, y->_right))
565 set_parent(y->_right, x, IS_LEFT);
566 set_parent(y, get_parent(x), get_pos(x));
567 if (rcu_rbtree_is_nil(rbtree, get_parent(x)))
568 rbtree->root = y;
569 else if (x == get_parent(x)->_right) {
570 get_parent(x)->_right = y;
571 } else {
572 get_parent(x)->_left = y;
573 }
574 y->_right = x;
575 set_parent(x, y, IS_RIGHT);
576 unlock_test_mutex();
577 }
578
579 #endif
580
581 static void rcu_rbtree_insert_fixup(struct rcu_rbtree *rbtree,
582 struct rcu_rbtree_node *z)
583 {
584 struct rcu_rbtree_node *y;
585
586 dbg_printf("insert fixup %p\n", z->begin);
587 assert(!is_decay(rbtree->root));
588
589 while (get_parent(z)->color == COLOR_RED) {
590 if (get_parent(z) == get_parent(get_parent(z))->_left) {
591 y = get_parent(get_parent(z))->_right;
592 if (y->color == COLOR_RED) {
593 get_parent(z)->color = COLOR_BLACK;
594 y->color = COLOR_BLACK;
595 get_parent(get_parent(z))->color = COLOR_RED;
596 z = get_parent(get_parent(z));
597 } else {
598 if (z == get_parent(z)->_right) {
599 z = get_parent(z);
600 left_rotate(rbtree, z);
601 z = get_decay(z);
602 assert(!is_decay(rbtree->root));
603 }
604 get_parent(z)->color = COLOR_BLACK;
605 get_parent(get_parent(z))->color = COLOR_RED;
606 assert(!is_decay(z));
607 assert(!is_decay(get_parent(z)));
608 assert(!is_decay(get_parent(get_parent(z))));
609 right_rotate(rbtree, get_parent(get_parent(z)));
610 assert(!is_decay(z));
611 assert(!is_decay(rbtree->root));
612 }
613 } else {
614 y = get_parent(get_parent(z))->_left;
615 if (y->color == COLOR_RED) {
616 get_parent(z)->color = COLOR_BLACK;
617 y->color = COLOR_BLACK;
618 get_parent(get_parent(z))->color = COLOR_RED;
619 z = get_parent(get_parent(z));
620 } else {
621 if (z == get_parent(z)->_left) {
622 z = get_parent(z);
623 right_rotate(rbtree, z);
624 z = get_decay(z);
625 assert(!is_decay(rbtree->root));
626 }
627 get_parent(z)->color = COLOR_BLACK;
628 get_parent(get_parent(z))->color = COLOR_RED;
629 left_rotate(rbtree, get_parent(get_parent(z)));
630 assert(!is_decay(z));
631 assert(!is_decay(rbtree->root));
632 }
633 }
634 }
635 rbtree->root->color = COLOR_BLACK;
636 }
637
638 /*
639 * rcu_rbtree_insert - Insert a node in the RCU rbtree
640 *
641 * Returns 0 on success, or < 0 on error.
642 */
643 int rcu_rbtree_insert(struct rcu_rbtree *rbtree,
644 struct rcu_rbtree_node *z)
645 {
646 struct rcu_rbtree_node *x, *y;
647
648 dbg_printf("insert %p\n", z->begin);
649 assert(!is_decay(rbtree->root));
650
651 y = make_nil(rbtree);
652 x = rbtree->root;
653 while (!rcu_rbtree_is_nil(rbtree, x)) {
654 y = x;
655 if (rbtree->comp(z->begin, x->begin) < 0)
656 x = x->_left;
657 else
658 x = x->_right;
659 }
660
661 z->_left = make_nil(rbtree);
662 z->_right = make_nil(rbtree);
663 z->color = COLOR_RED;
664 z->decay_next = NULL;
665
666 if (rcu_rbtree_is_nil(rbtree, y))
667 set_parent(z, y, IS_RIGHT); /* pos arbitrary for root node */
668 else if (rbtree->comp(z->begin, y->begin) < 0)
669 set_parent(z, y, IS_LEFT);
670 else
671 set_parent(z, y, IS_RIGHT);
672
673 if (rcu_rbtree_is_nil(rbtree, y)) {
674 /*
675 * Order stores to z (children/parents) before stores
676 * that will make it visible to the rest of the tree.
677 */
678 cmm_smp_wmb();
679 _CMM_STORE_SHARED(rbtree->root, z);
680 } else if (rbtree->comp(z->begin, y->begin) < 0) {
681 set_left(rbtree, y, z);
682 /*
683 * Order stores to z (children/parents) before stores
684 * that will make it visible to the rest of the tree.
685 */
686 cmm_smp_wmb();
687 if (rcu_rbtree_is_nil(rbtree, y))
688 _CMM_STORE_SHARED(rbtree->root, z);
689 else if (get_pos(z) == IS_LEFT)
690 _CMM_STORE_SHARED(y->_left, z);
691 else
692 _CMM_STORE_SHARED(y->_right, z);
693 } else {
694 set_right(rbtree, y, z);
695 /*
696 * Order stores to z (children/parents) before stores
697 * that will make it visible to the rest of the tree.
698 */
699 cmm_smp_wmb();
700 if (rcu_rbtree_is_nil(rbtree, y))
701 _CMM_STORE_SHARED(rbtree->root, z);
702 else if (get_pos(z) == IS_LEFT)
703 _CMM_STORE_SHARED(y->_left, z);
704 else
705 _CMM_STORE_SHARED(y->_right, z);
706 }
707 rcu_rbtree_insert_fixup(rbtree, z);
708 /*
709 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
710 */
711 cmm_smp_wmc();
712 show_tree(rbtree);
713
714 return 0;
715 }
716
717 /*
718 * Transplant v into u position.
719 */
720
721 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
722
723 static
724 void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
725 struct rcu_rbtree_node *u,
726 struct rcu_rbtree_node *v,
727 unsigned int copy_parents)
728 {
729 dbg_printf("transplant %p\n", v->begin);
730
731 if (!rcu_rbtree_is_nil(rbtree, v))
732 v = dup_decay_node(rbtree, v);
733
734 if (rcu_rbtree_is_nil(rbtree, get_parent(u))) {
735 /* pos is arbitrary for root node */
736 set_parent(v, get_parent(u), IS_RIGHT);
737 cmm_smp_wmb(); /* write into node before publish */
738 _CMM_STORE_SHARED(rbtree->root, v);
739 } else {
740 set_parent(v, get_parent(u), get_pos(u));
741
742 if (get_pos(u) == IS_LEFT)
743 set_left(rbtree, get_parent(u), v);
744 else
745 set_right(rbtree, get_parent(u), v);
746
747 cmm_smp_wmb(); /* write into node before publish */
748
749 if (rcu_rbtree_is_nil(rbtree, get_parent(u)))
750 _CMM_STORE_SHARED(rbtree->root, v);
751 else if (get_pos(u) == IS_LEFT)
752 _CMM_STORE_SHARED(get_parent(u)->_left, v);
753 else
754 _CMM_STORE_SHARED(get_parent(u)->_right, v);
755 }
756
757 /* Point children to new copy (parent only used by updates/next/prev) */
758 if (!rcu_rbtree_is_nil(rbtree, v)) {
759 set_parent(v->_right, get_decay(get_parent(v->_right)),
760 get_pos(v->_right));
761 set_parent(v->_left, get_decay(get_parent(v->_left)),
762 get_pos(v->_left));
763 }
764 assert(!is_decay(rbtree->root));
765 }
766
767 #else
768
769 /* Non-RCU version */
770 static
771 void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
772 struct rcu_rbtree_node *u,
773 struct rcu_rbtree_node *v,
774 unsigned int copy_parents)
775 {
776 dbg_printf("transplant %p\n", v->begin);
777
778 lock_test_mutex();
779 if (rcu_rbtree_is_nil(rbtree, get_parent(u)))
780 rbtree->root = v;
781 else if (u == get_parent(u)->_left)
782 get_parent(u)->_left = v;
783 else
784 get_parent(u)->_right = v;
785 set_parent(v, get_parent(u), get_pos(u));
786 unlock_test_mutex();
787 }
788
789 #endif
790
791 static void rcu_rbtree_remove_fixup(struct rcu_rbtree *rbtree,
792 struct rcu_rbtree_node *x)
793 {
794 dbg_printf("remove fixup %p\n", x->begin);
795
796 while (x != rbtree->root && x->color == COLOR_BLACK) {
797 assert(!is_decay(get_parent(x)));
798 assert(!is_decay(get_parent(x)->_left));
799 if (x == get_parent(x)->_left) {
800 struct rcu_rbtree_node *w;
801
802 w = get_parent(x)->_right;
803
804 if (w->color == COLOR_RED) {
805 w->color = COLOR_BLACK;
806 get_parent(x)->color = COLOR_RED;
807 left_rotate(rbtree, get_parent(x));
808 x = get_decay(x);
809 assert(!is_decay(rbtree->root));
810 w = get_parent(x)->_right;
811 }
812 if (w->_left->color == COLOR_BLACK
813 && w->_right->color == COLOR_BLACK) {
814 w->color = COLOR_RED;
815 x = get_parent(x);
816 assert(!is_decay(rbtree->root));
817 assert(!is_decay(x));
818 } else {
819 if (w->_right->color == COLOR_BLACK) {
820 w->_left->color = COLOR_BLACK;
821 w->color = COLOR_RED;
822 right_rotate(rbtree, w);
823 assert(!is_decay(rbtree->root));
824 x = get_decay(x);
825 w = get_parent(x)->_right;
826 }
827 w->color = get_parent(x)->color;
828 get_parent(x)->color = COLOR_BLACK;
829 w->_right->color = COLOR_BLACK;
830 left_rotate(rbtree, get_parent(x));
831 assert(!is_decay(rbtree->root));
832 x = rbtree->root;
833 }
834 } else {
835 struct rcu_rbtree_node *w;
836
837 w = get_parent(x)->_left;
838
839 if (w->color == COLOR_RED) {
840 w->color = COLOR_BLACK;
841 get_parent(x)->color = COLOR_RED;
842 right_rotate(rbtree, get_parent(x));
843 assert(!is_decay(rbtree->root));
844 x = get_decay(x);
845 w = get_parent(x)->_left;
846 }
847 if (w->_right->color == COLOR_BLACK
848 && w->_left->color == COLOR_BLACK) {
849 w->color = COLOR_RED;
850 x = get_parent(x);
851 assert(!is_decay(rbtree->root));
852 assert(!is_decay(x));
853 } else {
854 if (w->_left->color == COLOR_BLACK) {
855 w->_right->color = COLOR_BLACK;
856 w->color = COLOR_RED;
857 left_rotate(rbtree, w);
858 assert(!is_decay(rbtree->root));
859 x = get_decay(x);
860 w = get_parent(x)->_left;
861 }
862 w->color = get_parent(x)->color;
863 get_parent(x)->color = COLOR_BLACK;
864 w->_left->color = COLOR_BLACK;
865 right_rotate(rbtree, get_parent(x));
866 assert(!is_decay(rbtree->root));
867 x = rbtree->root;
868 }
869 }
870 }
871 x->color = COLOR_BLACK;
872 }
873
874 /*
875 * Delete z. All non-copied children left/right positions are unchanged.
876 */
877 static
878 void rcu_rbtree_remove_nonil(struct rcu_rbtree *rbtree,
879 struct rcu_rbtree_node *z,
880 struct rcu_rbtree_node *y)
881 {
882 struct rcu_rbtree_node *x;
883
884 dbg_printf("remove nonil %p\n", z->begin);
885 show_tree(rbtree);
886
887 assert(!is_decay(z));
888 assert(!is_decay(y));
889 assert(!is_decay(y->_right));
890 assert(!is_decay(get_parent(y)));
891 x = y->_right;
892 assert(!is_decay(x));
893 if (get_parent(y) == z) {
894 y = dup_decay_node(rbtree, y);
895 set_parent(x, y, get_pos(x)); /* parent for nil */
896 /* y is z's right node: set left will just update y */
897 set_left(rbtree, y, z->_left);
898 rcu_rbtree_transplant(rbtree, z, y, 1);
899 } else {
900 struct rcu_rbtree_node *oy_right, *z_right;
901
902 /*
903 * Need to make sure y is always visible by readers.
904 */
905 y = rcu_rbtree_min_dup_decay(rbtree, z->_right, &z_right);
906 assert(!is_decay(y));
907 assert(!is_decay(z));
908 oy_right = y->_right;
909
910 /*
911 * The max child begin of z_right does not change, because
912 * we're only changing its left children.
913 */
914 y->_right = z_right;
915 set_parent(y->_right, y, IS_RIGHT);
916 assert(!is_decay(z->_left));
917 y->_left = z->_left;
918 assert(!is_decay(oy_right));
919 /*
920 * Transplant of oy_right to old y's location will only
921 * trigger a min/max update of the already copied branch
922 * (which is not visible yet). We are transplanting
923 * oy_right as a left child of old y's parent, so the
924 * min values update propagated upward necessarily stops
925 * at z_right.
926 */
927 rcu_rbtree_transplant(rbtree, y, oy_right, 0);
928 rcu_rbtree_transplant(rbtree, z, y, 1);
929 /* Update children */
930 (void) rcu_rbtree_min_update_decay(rbtree, y->_right);
931 }
932 y = get_decay(y);
933 assert(!is_decay(z));
934 assert(!is_decay(z->_left));
935 y->color = z->color;
936 set_parent(y->_left, y, IS_LEFT);
937 set_parent(y->_right, get_decay(get_parent(y->_right)), IS_RIGHT);
938 assert(!is_decay(y->_left));
939 assert(!is_decay(y->_right));
940 }
941
942 int rcu_rbtree_remove(struct rcu_rbtree *rbtree,
943 struct rcu_rbtree_node *z)
944 {
945 struct rcu_rbtree_node *x, *y;
946 unsigned int y_original_color;
947
948 assert(!is_decay(rbtree->root));
949 dbg_printf("remove %p\n", z->begin);
950 show_tree(rbtree);
951
952 assert(!is_decay(z));
953 y = z;
954 y_original_color = y->color;
955
956 if (rcu_rbtree_is_nil(rbtree, z->_left)) {
957 rcu_rbtree_transplant(rbtree, z, z->_right, 1);
958 assert(!is_decay(z));
959 x = get_decay(z->_right);
960 show_tree(rbtree);
961 } else if (rcu_rbtree_is_nil(rbtree, z->_right)) {
962 rcu_rbtree_transplant(rbtree, z, z->_left, 1);
963 assert(!is_decay(z));
964 x = get_decay(z->_left);
965 show_tree(rbtree);
966 } else {
967 y = rcu_rbtree_min(rbtree, z->_right);
968 assert(!is_decay(y));
969 y_original_color = y->color;
970 x = y->_right;
971 rcu_rbtree_remove_nonil(rbtree, z, y);
972 x = get_decay(x);
973 show_tree(rbtree);
974 }
975 if (y_original_color == COLOR_BLACK)
976 rcu_rbtree_remove_fixup(rbtree, x);
977 show_tree(rbtree);
978 /*
979 * Commit all _CMM_STORE_SHARED().
980 */
981 cmm_smp_wmc();
982
983 return 0;
984 }
This page took 0.048666 seconds and 5 git commands to generate.