Remove incorrectly duplicated set_left/set_right
[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 z->max_end = z->end;
666
667 if (rcu_rbtree_is_nil(rbtree, y))
668 set_parent(z, y, IS_RIGHT); /* pos arbitrary for root node */
669 else if (rbtree->comp(z->begin, y->begin) < 0)
670 set_parent(z, y, IS_LEFT);
671 else
672 set_parent(z, y, IS_RIGHT);
673
674 if (rcu_rbtree_is_nil(rbtree, y)) {
675 /*
676 * Order stores to z (children/parents) before stores
677 * that will make it visible to the rest of the tree.
678 */
679 cmm_smp_wmb();
680 _CMM_STORE_SHARED(rbtree->root, z);
681 } else if (rbtree->comp(z->begin, y->begin) < 0) {
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 /*
695 * Order stores to z (children/parents) before stores
696 * that will make it visible to the rest of the tree.
697 */
698 cmm_smp_wmb();
699 if (rcu_rbtree_is_nil(rbtree, y))
700 _CMM_STORE_SHARED(rbtree->root, z);
701 else if (get_pos(z) == IS_LEFT)
702 _CMM_STORE_SHARED(y->_left, z);
703 else
704 _CMM_STORE_SHARED(y->_right, z);
705 }
706 rcu_rbtree_insert_fixup(rbtree, z);
707 /*
708 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
709 */
710 cmm_smp_wmc();
711 show_tree(rbtree);
712
713 return 0;
714 }
715
716 /*
717 * Transplant v into u position.
718 */
719
720 #ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
721
722 static
723 void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
724 struct rcu_rbtree_node *u,
725 struct rcu_rbtree_node *v,
726 unsigned int copy_parents)
727 {
728 dbg_printf("transplant %p\n", v->begin);
729
730 if (!rcu_rbtree_is_nil(rbtree, v))
731 v = dup_decay_node(rbtree, v);
732
733 if (rcu_rbtree_is_nil(rbtree, get_parent(u))) {
734 /* pos is arbitrary for root node */
735 set_parent(v, get_parent(u), IS_RIGHT);
736 cmm_smp_wmb(); /* write into node before publish */
737 _CMM_STORE_SHARED(rbtree->root, v);
738 } else {
739 set_parent(v, get_parent(u), get_pos(u));
740 cmm_smp_wmb(); /* write into node before publish */
741
742 if (rcu_rbtree_is_nil(rbtree, get_parent(u)))
743 _CMM_STORE_SHARED(rbtree->root, v);
744 else if (get_pos(u) == IS_LEFT)
745 _CMM_STORE_SHARED(get_parent(u)->_left, v);
746 else
747 _CMM_STORE_SHARED(get_parent(u)->_right, v);
748 }
749
750 /* Point children to new copy (parent only used by updates/next/prev) */
751 if (!rcu_rbtree_is_nil(rbtree, v)) {
752 set_parent(v->_right, get_decay(get_parent(v->_right)),
753 get_pos(v->_right));
754 set_parent(v->_left, get_decay(get_parent(v->_left)),
755 get_pos(v->_left));
756 }
757 assert(!is_decay(rbtree->root));
758 }
759
760 #else
761
762 /* Non-RCU version */
763 static
764 void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
765 struct rcu_rbtree_node *u,
766 struct rcu_rbtree_node *v,
767 unsigned int copy_parents)
768 {
769 dbg_printf("transplant %p\n", v->begin);
770
771 lock_test_mutex();
772 if (rcu_rbtree_is_nil(rbtree, get_parent(u)))
773 rbtree->root = v;
774 else if (u == get_parent(u)->_left)
775 get_parent(u)->_left = v;
776 else
777 get_parent(u)->_right = v;
778 set_parent(v, get_parent(u), get_pos(u));
779 unlock_test_mutex();
780 }
781
782 #endif
783
784 static void rcu_rbtree_remove_fixup(struct rcu_rbtree *rbtree,
785 struct rcu_rbtree_node *x)
786 {
787 dbg_printf("remove fixup %p\n", x->begin);
788
789 while (x != rbtree->root && x->color == COLOR_BLACK) {
790 assert(!is_decay(get_parent(x)));
791 assert(!is_decay(get_parent(x)->_left));
792 if (x == get_parent(x)->_left) {
793 struct rcu_rbtree_node *w;
794
795 w = get_parent(x)->_right;
796
797 if (w->color == COLOR_RED) {
798 w->color = COLOR_BLACK;
799 get_parent(x)->color = COLOR_RED;
800 left_rotate(rbtree, get_parent(x));
801 x = get_decay(x);
802 assert(!is_decay(rbtree->root));
803 w = get_parent(x)->_right;
804 }
805 if (w->_left->color == COLOR_BLACK
806 && w->_right->color == COLOR_BLACK) {
807 w->color = COLOR_RED;
808 x = get_parent(x);
809 assert(!is_decay(rbtree->root));
810 assert(!is_decay(x));
811 } else {
812 if (w->_right->color == COLOR_BLACK) {
813 w->_left->color = COLOR_BLACK;
814 w->color = COLOR_RED;
815 right_rotate(rbtree, w);
816 assert(!is_decay(rbtree->root));
817 x = get_decay(x);
818 w = get_parent(x)->_right;
819 }
820 w->color = get_parent(x)->color;
821 get_parent(x)->color = COLOR_BLACK;
822 w->_right->color = COLOR_BLACK;
823 left_rotate(rbtree, get_parent(x));
824 assert(!is_decay(rbtree->root));
825 x = rbtree->root;
826 }
827 } else {
828 struct rcu_rbtree_node *w;
829
830 w = get_parent(x)->_left;
831
832 if (w->color == COLOR_RED) {
833 w->color = COLOR_BLACK;
834 get_parent(x)->color = COLOR_RED;
835 right_rotate(rbtree, get_parent(x));
836 assert(!is_decay(rbtree->root));
837 x = get_decay(x);
838 w = get_parent(x)->_left;
839 }
840 if (w->_right->color == COLOR_BLACK
841 && w->_left->color == COLOR_BLACK) {
842 w->color = COLOR_RED;
843 x = get_parent(x);
844 assert(!is_decay(rbtree->root));
845 assert(!is_decay(x));
846 } else {
847 if (w->_left->color == COLOR_BLACK) {
848 w->_right->color = COLOR_BLACK;
849 w->color = COLOR_RED;
850 left_rotate(rbtree, w);
851 assert(!is_decay(rbtree->root));
852 x = get_decay(x);
853 w = get_parent(x)->_left;
854 }
855 w->color = get_parent(x)->color;
856 get_parent(x)->color = COLOR_BLACK;
857 w->_left->color = COLOR_BLACK;
858 right_rotate(rbtree, get_parent(x));
859 assert(!is_decay(rbtree->root));
860 x = rbtree->root;
861 }
862 }
863 }
864 x->color = COLOR_BLACK;
865 }
866
867 /*
868 * Delete z. All non-copied children left/right positions are unchanged.
869 */
870 static
871 void rcu_rbtree_remove_nonil(struct rcu_rbtree *rbtree,
872 struct rcu_rbtree_node *z,
873 struct rcu_rbtree_node *y)
874 {
875 struct rcu_rbtree_node *x;
876
877 dbg_printf("remove nonil %p\n", z->begin);
878 show_tree(rbtree);
879
880 assert(!is_decay(z));
881 assert(!is_decay(y));
882 assert(!is_decay(y->_right));
883 assert(!is_decay(get_parent(y)));
884 x = y->_right;
885 assert(!is_decay(x));
886 if (get_parent(y) == z) {
887 y = dup_decay_node(rbtree, y);
888 set_parent(x, y, get_pos(x)); /* parent for nil */
889 /* y is z's right node: set left will just update y */
890 set_left(rbtree, y, z->_left);
891 rcu_rbtree_transplant(rbtree, z, y, 1);
892 } else {
893 struct rcu_rbtree_node *oy_right, *z_right;
894
895 /*
896 * Need to make sure y is always visible by readers.
897 */
898 y = rcu_rbtree_min_dup_decay(rbtree, z->_right, &z_right);
899 assert(!is_decay(y));
900 assert(!is_decay(z));
901 oy_right = y->_right;
902
903 /*
904 * The max child begin of z_right does not change, because
905 * we're only changing its left children.
906 */
907 y->_right = z_right;
908 set_parent(y->_right, y, IS_RIGHT);
909 assert(!is_decay(z->_left));
910 y->_left = z->_left;
911 assert(!is_decay(oy_right));
912 /*
913 * Transplant of oy_right to old y's location will only
914 * trigger a min/max update of the already copied branch
915 * (which is not visible yet). We are transplanting
916 * oy_right as a left child of old y's parent, so the
917 * min values update propagated upward necessarily stops
918 * at z_right.
919 */
920 rcu_rbtree_transplant(rbtree, y, oy_right, 0);
921 rcu_rbtree_transplant(rbtree, z, y, 1);
922 /* Update children */
923 (void) rcu_rbtree_min_update_decay(rbtree, y->_right);
924 }
925 y = get_decay(y);
926 assert(!is_decay(z));
927 assert(!is_decay(z->_left));
928 y->color = z->color;
929 set_parent(y->_left, y, IS_LEFT);
930 set_parent(y->_right, get_decay(get_parent(y->_right)), IS_RIGHT);
931 assert(!is_decay(y->_left));
932 assert(!is_decay(y->_right));
933 }
934
935 int rcu_rbtree_remove(struct rcu_rbtree *rbtree,
936 struct rcu_rbtree_node *z)
937 {
938 struct rcu_rbtree_node *x, *y;
939 unsigned int y_original_color;
940
941 assert(!is_decay(rbtree->root));
942 dbg_printf("remove %p\n", z->begin);
943 show_tree(rbtree);
944
945 assert(!is_decay(z));
946 y = z;
947 y_original_color = y->color;
948
949 if (rcu_rbtree_is_nil(rbtree, z->_left)) {
950 rcu_rbtree_transplant(rbtree, z, z->_right, 1);
951 assert(!is_decay(z));
952 x = get_decay(z->_right);
953 show_tree(rbtree);
954 } else if (rcu_rbtree_is_nil(rbtree, z->_right)) {
955 rcu_rbtree_transplant(rbtree, z, z->_left, 1);
956 assert(!is_decay(z));
957 x = get_decay(z->_left);
958 show_tree(rbtree);
959 } else {
960 y = rcu_rbtree_min(rbtree, z->_right);
961 assert(!is_decay(y));
962 y_original_color = y->color;
963 x = y->_right;
964 rcu_rbtree_remove_nonil(rbtree, z, y);
965 x = get_decay(x);
966 show_tree(rbtree);
967 }
968 if (y_original_color == COLOR_BLACK)
969 rcu_rbtree_remove_fixup(rbtree, x);
970 show_tree(rbtree);
971 /*
972 * Commit all _CMM_STORE_SHARED().
973 */
974 cmm_smp_wmc();
975
976 return 0;
977 }
This page took 0.052243 seconds and 5 git commands to generate.