RCU rbtree test: handle duplicate random numbers
[userspace-rcu.git] / urcu-rbtree.c
CommitLineData
dff86257
MD
1/*
2 * urcu-rbtree.c
3 *
4 * Userspace RCU library - Red-Black Tree
5 *
6 * Copyright (c) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 * Implementation of RCU-adapted data structures and operations based on the RB
23 * tree algorithms found in chapter 12 of:
24 *
25 * Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and
26 * Clifford Stein. Introduction to Algorithms, Third Edition. The MIT
27 * Press, September 2009.
28 */
29
30#define _BSD_SOURCE
31#define _LGPL_SOURCE
32
33#include <stdio.h>
34#include <pthread.h>
35#include <assert.h>
269a9ef6 36#include <string.h>
230dd288 37#include <unistd.h>
dff86257
MD
38
39#include <urcu/rcurbtree.h>
40#include <urcu-pointer.h>
c479601c 41#include <urcu-call-rcu.h>
dff86257 42
dff86257
MD
43#ifdef DEBUG
44#define dbg_printf(args...) printf(args)
45#else
46#define dbg_printf(args...)
47#endif
48
6daf6090
MD
49/*
50 * Undefine this to enable the non-RCU rotate and transplant functions
51 * (for debugging).
52 */
dbe4ae98
MD
53#define RBTREE_RCU_SUPPORT_ROTATE_LEFT
54#define RBTREE_RCU_SUPPORT_ROTATE_RIGHT
6daf6090
MD
55#define RBTREE_RCU_SUPPORT_TRANSPLANT
56
230dd288
MD
57#ifdef EXTRA_DEBUG
58static pthread_mutex_t test_mutex = PTHREAD_MUTEX_INITIALIZER;
59static pthread_mutex_t outer_mutex = PTHREAD_MUTEX_INITIALIZER;
60
61static
62void lock_outer_mutex(void)
63{
64 pthread_mutex_lock(&outer_mutex);
65}
66
67static
68void unlock_outer_mutex(void)
69{
70 pthread_mutex_unlock(&outer_mutex);
71}
72
73static
74void lock_test_mutex(void)
75{
76 pthread_mutex_lock(&test_mutex);
77}
78
79static
80void unlock_test_mutex(void)
81{
82 pthread_mutex_unlock(&test_mutex);
83}
84#endif
85
7ba89e62
MD
86static
87void set_parent(struct rcu_rbtree_node *node,
88 struct rcu_rbtree_node *parent,
89 unsigned int pos)
90{
91 node->parent = ((unsigned long) parent) | pos;
92}
93
94static
95struct rcu_rbtree_node *get_parent(struct rcu_rbtree_node *node)
96{
97 return (struct rcu_rbtree_node *) (node->parent & ~1UL);
98}
99
100static
101unsigned int get_pos(struct rcu_rbtree_node *node)
102{
103 return (unsigned int) (node->parent & 1UL);
104}
105
106static
107struct rcu_rbtree_node *get_parent_and_pos(struct rcu_rbtree_node *node,
108 unsigned int *pos)
109{
110 unsigned long parent_pos = rcu_dereference(node->parent);
111
112 *pos = (unsigned int) (parent_pos & 1UL);
113 return (struct rcu_rbtree_node *) (parent_pos & ~1UL);
114}
115
269a9ef6
MD
116static
117void set_decay(struct rcu_rbtree_node *x, struct rcu_rbtree_node *xc)
118{
119 x->decay_next = xc;
120}
121
122static
123struct rcu_rbtree_node *get_decay(struct rcu_rbtree_node *x)
124{
dbe4ae98
MD
125 if (!x)
126 return NULL;
269a9ef6
MD
127 while (x->decay_next)
128 x = x->decay_next;
129 return x;
130}
131
132static
133struct rcu_rbtree_node *is_decay(struct rcu_rbtree_node *x)
134{
135 return x->decay_next;
136}
137
138static
139struct rcu_rbtree_node *dup_decay_node(struct rcu_rbtree *rbtree,
140 struct rcu_rbtree_node *x)
141{
142 struct rcu_rbtree_node *xc;
143
144 if (rcu_rbtree_is_nil(x))
145 return x;
146
147 xc = rbtree->rballoc();
148 memcpy(xc, x, sizeof(struct rcu_rbtree_node));
149 xc->decay_next = NULL;
150 set_decay(x, xc);
c479601c 151 call_rcu(&x->head, rbtree->rbfree);
269a9ef6
MD
152 return xc;
153}
154
dff86257
MD
155/*
156 * TODO
157 * Deal with memory allocation errors.
158 * Can be ensured by reserving a pool of memory entries before doing the
159 * insertion, which will have to be function of number of
160 * transplantations/rotations required for the operation.
161 */
162
5d2c985d 163#ifdef DEBUG
dff86257
MD
164static
165void show_tree(struct rcu_rbtree *rbtree)
166{
167 struct rcu_rbtree_node *node;
168
169 node = rcu_rbtree_min(rbtree, rbtree->root);
170 while (!rcu_rbtree_is_nil(node)) {
269a9ef6 171 assert(!is_decay(node));
dff86257
MD
172 printf("{ 0x%lX p:%lX r:%lX l:%lX %s %s %s} ",
173 (unsigned long)node->key,
7ba89e62 174 (unsigned long) get_parent(node)->key,
269a9ef6
MD
175 (unsigned long) node->right->key,
176 (unsigned long) node->left->key,
dff86257 177 node->color ? "red" : "black",
7ba89e62 178 get_pos(node) ? "right" : "left",
dff86257
MD
179 node->nil ? "nil" : "");
180 node = rcu_rbtree_next(rbtree, node);
181 }
182 printf("\n");
183}
5d2c985d
MD
184#else /* DEBUG */
185static
186void show_tree(struct rcu_rbtree *rbtree)
187{
188}
189#endif /* DEBUG */
dff86257
MD
190
191static
192struct rcu_rbtree_node *make_nil(struct rcu_rbtree *rbtree)
193{
194 return &rbtree->nil_node;
195}
196
197/*
198 * Iterative rbtree search.
199 */
200struct rcu_rbtree_node* rcu_rbtree_search(struct rcu_rbtree *rbtree,
201 struct rcu_rbtree_node *x,
202 void *k)
203{
204 x = rcu_dereference(x);
205
206 while (!rcu_rbtree_is_nil(x) && k != x->key) {
230dd288 207 usleep(10);
dff86257
MD
208 if (rbtree->comp(k, x->key) < 0)
209 x = rcu_dereference(x->left);
210 else
211 x = rcu_dereference(x->right);
212 }
213 return x;
214}
215
230dd288
MD
216static
217struct rcu_rbtree_node *rcu_rbtree_min_dup_decay(struct rcu_rbtree *rbtree,
218 struct rcu_rbtree_node *x,
219 struct rcu_rbtree_node **zr)
220{
221 struct rcu_rbtree_node *xl;
222
223 x = rcu_dereference(x);
224
225 if (rcu_rbtree_is_nil(x)) {
226 *zr = x;
227 return x;
228 } else
229 *zr = x = dup_decay_node(rbtree, x);
230
231 while (!rcu_rbtree_is_nil(xl = rcu_dereference(x->left))) {
232 x = dup_decay_node(rbtree, xl);
7ba89e62
MD
233 set_parent(x, get_decay(get_parent(x)), get_pos(x));
234 get_parent(x)->left = get_decay(get_parent(x)->left);
230dd288
MD
235 }
236 return x;
237}
238
239static
240struct rcu_rbtree_node *rcu_rbtree_min_update_decay(struct rcu_rbtree *rbtree,
241 struct rcu_rbtree_node *x)
242{
243 struct rcu_rbtree_node *xl;
244
245 x = rcu_dereference(x);
246
247 if (rcu_rbtree_is_nil(x))
248 return x;
249 else {
7ba89e62
MD
250 set_parent(x->right, get_decay(get_parent(x->right)),
251 get_pos(x->right));
252 set_parent(x->left, get_decay(get_parent(x->left)),
253 get_pos(x->left));
230dd288
MD
254 }
255
256 while (!rcu_rbtree_is_nil(xl = rcu_dereference(x->left))) {
257 x = xl;
7ba89e62
MD
258 set_parent(x->right, get_decay(get_parent(x->right)),
259 get_pos(x->right));
260 set_parent(x->left, get_decay(get_parent(x->left)),
261 get_pos(x->left));
230dd288
MD
262 }
263 return x;
264}
265
dff86257
MD
266struct rcu_rbtree_node *rcu_rbtree_min(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(x))
274 return x;
275
276 while (!rcu_rbtree_is_nil(xl = rcu_dereference(x->left)))
277 x = xl;
278 return x;
279}
280
281struct rcu_rbtree_node *rcu_rbtree_max(struct rcu_rbtree *rbtree,
282 struct rcu_rbtree_node *x)
283{
284 struct rcu_rbtree_node *xr;
285
286 x = rcu_dereference(x);
287
288 if (rcu_rbtree_is_nil(x))
289 return x;
290
291 while (!rcu_rbtree_is_nil(xr = rcu_dereference(x->right)))
292 x = xr;
293 return x;
294}
295
296/*
297 * FIXME:
298 * Updates should wait for a grace period between update of the
299 * redirect pointer and update of the parent child pointer. This is to make sure
300 * that no reference to the old entry exist.
301 */
302
303/*
7ba89e62
MD
304 * RCU read lock must be held across the next/prev calls to ensure validity of
305 * the returned node.
dff86257
MD
306 */
307struct rcu_rbtree_node *rcu_rbtree_next(struct rcu_rbtree *rbtree,
308 struct rcu_rbtree_node *x)
309{
269a9ef6 310 struct rcu_rbtree_node *xr, *y;
7ba89e62 311 unsigned int x_pos;
dff86257
MD
312
313 x = rcu_dereference(x);
314
315 if (!rcu_rbtree_is_nil(xr = rcu_dereference(x->right)))
316 return rcu_rbtree_min(rbtree, xr);
7ba89e62
MD
317 y = get_parent_and_pos(x, &x_pos);
318 while (!rcu_rbtree_is_nil(y) && x_pos == IS_RIGHT) {
dff86257 319 x = y;
7ba89e62 320 y = get_parent_and_pos(y, &x_pos);
dff86257
MD
321 }
322 return y;
323}
324
325struct rcu_rbtree_node *rcu_rbtree_prev(struct rcu_rbtree *rbtree,
326 struct rcu_rbtree_node *x)
327{
269a9ef6 328 struct rcu_rbtree_node *xl, *y;
7ba89e62 329 unsigned int x_pos;
dff86257
MD
330
331 x = rcu_dereference(x);
332
333 if (!rcu_rbtree_is_nil(xl = rcu_dereference(x->left)))
4aa30442 334 return rcu_rbtree_max(rbtree, xl);
7ba89e62
MD
335 y = get_parent_and_pos(x, &x_pos);
336 while (!rcu_rbtree_is_nil(y) && x_pos == IS_LEFT) {
dff86257 337 x = y;
7ba89e62 338 y = get_parent_and_pos(y, &x_pos);
dff86257
MD
339 }
340 return y;
341}
342
343/*
344 * We have to ensure these assumptions are correct for prev/next
345 * traversal:
346 *
347 * with x being a right child, the assumption that:
7ba89e62 348 * get_parent(x)->right == x
dff86257 349 * or if x is a left child, the assumption that:
7ba89e62 350 * get_parent(x)->left == x
dff86257
MD
351 *
352 * This explains why we have to allocate a vc copy of the node for left_rotate,
353 * right_rotate and transplant operations.
354 *
355 * We always ensure that the right/left child and correct parent is set in the
356 * node copies *before* we reparent the children and make the upper-level point
357 * to the copy.
358 */
359
360/* RCU: copy x and y, atomically point to new versions. GC old. */
361/* Should be eventually followed by a cmm_smp_wmc() */
dff86257 362
dbe4ae98
MD
363#ifdef RBTREE_RCU_SUPPORT_ROTATE_LEFT
364
dff86257 365static
269a9ef6
MD
366void left_rotate(struct rcu_rbtree *rbtree,
367 struct rcu_rbtree_node *x)
dff86257 368{
676dd8b6
MD
369 struct rcu_rbtree_node *y, *y_left, *x_p;
370 unsigned int x_pos;
dff86257 371
dff86257 372 y = x->right;
676dd8b6 373 y_left = y->left;
269a9ef6
MD
374
375 /* Now operate on new copy, decay old versions */
dbe4ae98
MD
376 x = dup_decay_node(rbtree, x);
377 y = dup_decay_node(rbtree, y);
378 y_left = dup_decay_node(rbtree, y_left);
269a9ef6 379
7ba89e62
MD
380 x_pos = get_pos(x);
381 x_p = get_parent(x);
676dd8b6
MD
382
383 /* Internal node modifications */
384 x->right = y_left;
7ba89e62
MD
385 set_parent(y, get_parent(x), get_pos(x));
386 set_parent(x, y, IS_LEFT);
676dd8b6 387 y->left = x;
7ba89e62
MD
388 if (!rcu_rbtree_is_nil(y_left))
389 set_parent(y_left, x, IS_RIGHT);
676dd8b6
MD
390
391 cmm_smp_wmb(); /* write into node before publish */
392
393 /* External references update (visible by readers) */
394 if (rcu_rbtree_is_nil(x_p))
395 _CMM_STORE_SHARED(rbtree->root, y);
396 else if (x_pos == IS_LEFT)
397 _CMM_STORE_SHARED(x_p->left, y);
398 else
399 _CMM_STORE_SHARED(x_p->right, y);
400
dbe4ae98 401 /* Point children to new copy (parent only used by updates/next/prev) */
7ba89e62
MD
402 set_parent(x->left, get_decay(get_parent(x->left)),
403 get_pos(x->left));
404 set_parent(y->right, get_decay(get_parent(y->right)),
405 get_pos(y->right));
dbe4ae98 406 if (!rcu_rbtree_is_nil(y_left)) {
7ba89e62
MD
407 set_parent(y_left->right, get_decay(get_parent(y_left->right)),
408 get_pos(y_left->right));
409 set_parent(y_left->left, get_decay(get_parent(y_left->left)),
410 get_pos(y_left->left));
dbe4ae98 411 }
269a9ef6
MD
412
413 /* Sanity checks */
7ba89e62
MD
414 assert(y == rbtree->root || get_parent(y)->left == y || get_parent(y)->right == y);
415 assert(x == rbtree->root || get_parent(x)->left == x || get_parent(x)->right == x);
416 assert(rcu_rbtree_is_nil(x->right) || get_parent(x->right) == x);
417 assert(rcu_rbtree_is_nil(x->left) || get_parent(x->left) == x);
418 assert(rcu_rbtree_is_nil(y->right) || get_parent(y->right) == y);
419 assert(rcu_rbtree_is_nil(y->left) || get_parent(y->left) == y);
269a9ef6
MD
420 assert(!is_decay(rbtree->root));
421 assert(!is_decay(x));
422 assert(!is_decay(y));
423 assert(!is_decay(x->right));
424 assert(!is_decay(x->left));
425 assert(!is_decay(y->right));
426 assert(!is_decay(y->left));
dff86257
MD
427}
428
dbe4ae98
MD
429#else
430
431/* non-rcu version */
432static
433void left_rotate(struct rcu_rbtree *rbtree,
434 struct rcu_rbtree_node *x)
435{
436 struct rcu_rbtree_node *y;
437
230dd288 438 lock_test_mutex();
dbe4ae98
MD
439 y = x->right;
440 x->right = y->left;
7ba89e62
MD
441 if (!rcu_rbtree_is_nil(y->left))
442 set_parent(y->left, x, IS_RIGHT);
443 set_parent(y, get_parent(x), get_pos(x));
444 if (rcu_rbtree_is_nil(get_parent(x)))
dbe4ae98 445 rbtree->root = y;
7ba89e62
MD
446 else if (x == get_parent(x)->left) {
447 get_parent(x)->left = y;
dbe4ae98 448 } else {
7ba89e62 449 get_parent(x)->right = y;
dbe4ae98
MD
450 }
451 y->left = x;
7ba89e62 452 set_parent(x, y, IS_LEFT);
230dd288 453 unlock_test_mutex();
dbe4ae98
MD
454}
455
456#endif
457
458#ifdef RBTREE_RCU_SUPPORT_ROTATE_RIGHT
dff86257 459static
269a9ef6
MD
460void right_rotate(struct rcu_rbtree *rbtree,
461 struct rcu_rbtree_node *x)
dff86257 462{
676dd8b6
MD
463 struct rcu_rbtree_node *y, *y_right, *x_p;
464 unsigned int x_pos;
dff86257 465
dff86257 466 y = x->left;
676dd8b6 467 y_right = y->right;
269a9ef6
MD
468
469 /* Now operate on new copy, decay old versions */
dbe4ae98
MD
470 x = dup_decay_node(rbtree, x);
471 y = dup_decay_node(rbtree, y);
472 y_right = dup_decay_node(rbtree, y_right);
269a9ef6 473
7ba89e62
MD
474 x_pos = get_pos(x);
475 x_p = get_parent(x);
676dd8b6
MD
476
477 /* Internal node modifications */
478 x->left = y_right;
7ba89e62
MD
479 set_parent(y, get_parent(x), get_pos(x));
480 set_parent(x, y, IS_RIGHT);
676dd8b6 481 y->right = x;
7ba89e62
MD
482 if (!rcu_rbtree_is_nil(y_right))
483 set_parent(y_right, x, IS_LEFT);
676dd8b6
MD
484
485 cmm_smp_wmb(); /* write into node before publish */
486
487 /* External references update (visible by readers) */
488 if (rcu_rbtree_is_nil(x_p))
489 _CMM_STORE_SHARED(rbtree->root, y);
490 else if (x_pos == IS_RIGHT)
491 _CMM_STORE_SHARED(x_p->right, y);
492 else
493 _CMM_STORE_SHARED(x_p->left, y);
494
dbe4ae98 495 /* Point children to new copy (parent only used by updates/next/prev) */
7ba89e62
MD
496 set_parent(x->right, get_decay(get_parent(x->right)),
497 get_pos(x->right));
498 set_parent(y->left, get_decay(get_parent(y->left)),
499 get_pos(y->left));
dbe4ae98 500 if (!rcu_rbtree_is_nil(y_right)) {
7ba89e62
MD
501 set_parent(y_right->left, get_decay(get_parent(y_right->left)),
502 get_pos(y_right->left));
503 set_parent(y_right->right, get_decay(get_parent(y_right->right)),
504 get_pos(y_right->right));
dbe4ae98 505 }
269a9ef6
MD
506
507 /* Sanity checks */
7ba89e62
MD
508 assert(y == rbtree->root || get_parent(y)->right == y || get_parent(y)->left == y);
509 assert(x == rbtree->root || get_parent(x)->right == x || get_parent(x)->left == x);
510 assert(rcu_rbtree_is_nil(x->left) || get_parent(x->left) == x);
511 assert(rcu_rbtree_is_nil(x->right) || get_parent(x->right) == x);
512 assert(rcu_rbtree_is_nil(y->left) || get_parent(y->left) == y);
513 assert(rcu_rbtree_is_nil(y->right) || get_parent(y->right) == y);
269a9ef6
MD
514 assert(!is_decay(rbtree->root));
515 assert(!is_decay(x));
516 assert(!is_decay(y));
517 assert(!is_decay(x->left));
518 assert(!is_decay(x->right));
519 assert(!is_decay(y->left));
520 assert(!is_decay(y->right));
dff86257
MD
521}
522
6daf6090
MD
523#else
524
dbe4ae98 525/* non-rcu version */
6daf6090
MD
526static
527void right_rotate(struct rcu_rbtree *rbtree,
528 struct rcu_rbtree_node *x)
529{
530 struct rcu_rbtree_node *y;
531
230dd288 532 lock_test_mutex();
6daf6090
MD
533 y = x->left;
534 x->left = y->right;
7ba89e62
MD
535 if (!rcu_rbtree_is_nil(y->right))
536 set_parent(y->right, x, IS_LEFT);
537 set_parent(y, get_parent(x), get_pos(x));
538 if (rcu_rbtree_is_nil(get_parent(x)))
6daf6090 539 rbtree->root = y;
7ba89e62
MD
540 else if (x == get_parent(x)->right) {
541 get_parent(x)->right = y;
6daf6090 542 } else {
7ba89e62 543 get_parent(x)->left = y;
6daf6090
MD
544 }
545 y->right = x;
7ba89e62 546 set_parent(x, y, IS_RIGHT);
230dd288 547 unlock_test_mutex();
6daf6090
MD
548}
549
550#endif
551
dff86257
MD
552static void rcu_rbtree_insert_fixup(struct rcu_rbtree *rbtree,
553 struct rcu_rbtree_node *z)
554{
555 struct rcu_rbtree_node *y;
556
557 dbg_printf("insert fixup %p\n", z->key);
269a9ef6 558 assert(!is_decay(rbtree->root));
dff86257 559
7ba89e62
MD
560 while (get_parent(z)->color == COLOR_RED) {
561 if (get_parent(z) == get_parent(get_parent(z))->left) {
562 y = get_parent(get_parent(z))->right;
dff86257 563 if (y->color == COLOR_RED) {
7ba89e62 564 get_parent(z)->color = COLOR_BLACK;
dff86257 565 y->color = COLOR_BLACK;
7ba89e62
MD
566 get_parent(get_parent(z))->color = COLOR_RED;
567 z = get_parent(get_parent(z));
dff86257 568 } else {
7ba89e62
MD
569 if (z == get_parent(z)->right) {
570 z = get_parent(z);
dff86257 571 left_rotate(rbtree, z);
269a9ef6
MD
572 z = get_decay(z);
573 assert(!is_decay(rbtree->root));
dff86257 574 }
7ba89e62
MD
575 get_parent(z)->color = COLOR_BLACK;
576 get_parent(get_parent(z))->color = COLOR_RED;
269a9ef6 577 assert(!is_decay(z));
7ba89e62
MD
578 assert(!is_decay(get_parent(z)));
579 assert(!is_decay(get_parent(get_parent(z))));
580 right_rotate(rbtree, get_parent(get_parent(z)));
269a9ef6
MD
581 assert(!is_decay(z));
582 assert(!is_decay(rbtree->root));
dff86257
MD
583 }
584 } else {
7ba89e62 585 y = get_parent(get_parent(z))->left;
dff86257 586 if (y->color == COLOR_RED) {
7ba89e62 587 get_parent(z)->color = COLOR_BLACK;
dff86257 588 y->color = COLOR_BLACK;
7ba89e62
MD
589 get_parent(get_parent(z))->color = COLOR_RED;
590 z = get_parent(get_parent(z));
dff86257 591 } else {
7ba89e62
MD
592 if (z == get_parent(z)->left) {
593 z = get_parent(z);
dff86257 594 right_rotate(rbtree, z);
269a9ef6
MD
595 z = get_decay(z);
596 assert(!is_decay(rbtree->root));
dff86257 597 }
7ba89e62
MD
598 get_parent(z)->color = COLOR_BLACK;
599 get_parent(get_parent(z))->color = COLOR_RED;
600 left_rotate(rbtree, get_parent(get_parent(z)));
269a9ef6
MD
601 assert(!is_decay(z));
602 assert(!is_decay(rbtree->root));
dff86257
MD
603 }
604 }
605 }
606 rbtree->root->color = COLOR_BLACK;
607}
608
609/*
610 * rcu_rbtree_insert - Insert a node in the RCU rbtree
611 *
612 * Returns 0 on success, or < 0 on error.
613 */
614int rcu_rbtree_insert(struct rcu_rbtree *rbtree,
615 struct rcu_rbtree_node *z)
616{
617 struct rcu_rbtree_node *x, *y;
618
619 dbg_printf("insert %p\n", z->key);
269a9ef6 620 assert(!is_decay(rbtree->root));
dff86257
MD
621
622 y = make_nil(rbtree);
623 if (!rbtree->root)
624 rbtree->root = make_nil(rbtree);
625 x = rbtree->root;
626 while (!rcu_rbtree_is_nil(x)) {
627 y = x;
628 if (rbtree->comp(z->key, x->key) < 0)
629 x = x->left;
630 else
631 x = x->right;
632 }
633
dff86257
MD
634 z->left = make_nil(rbtree);
635 z->right = make_nil(rbtree);
636 z->color = COLOR_RED;
637 z->nil = 0;
269a9ef6 638 z->decay_next = NULL;
dff86257
MD
639
640 if (rcu_rbtree_is_nil(y))
7ba89e62 641 set_parent(z, y, IS_RIGHT); /* pos arbitrary for root node */
dff86257 642 else if (rbtree->comp(z->key, y->key) < 0)
7ba89e62 643 set_parent(z, y, IS_LEFT);
dff86257 644 else
7ba89e62 645 set_parent(z, y, IS_RIGHT);
dff86257
MD
646
647 /*
648 * Order stores to z (children/parents) before stores that will make it
649 * visible to the rest of the tree.
650 */
651 cmm_smp_wmb();
652
653 if (rcu_rbtree_is_nil(y))
654 _CMM_STORE_SHARED(rbtree->root, z);
655 else if (rbtree->comp(z->key, y->key) < 0)
656 _CMM_STORE_SHARED(y->left, z);
657 else
658 _CMM_STORE_SHARED(y->right, z);
659 rcu_rbtree_insert_fixup(rbtree, z);
660 /*
661 * Make sure to commit all _CMM_STORE_SHARED() for non-coherent caches.
662 */
663 cmm_smp_wmc();
664 show_tree(rbtree);
665
666 return 0;
667}
668
669/*
670 * Transplant v into u position.
dff86257 671 */
6daf6090
MD
672
673#ifdef RBTREE_RCU_SUPPORT_TRANSPLANT
674
269a9ef6
MD
675static
676void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
677 struct rcu_rbtree_node *u,
678 struct rcu_rbtree_node *v)
dff86257 679{
dff86257
MD
680 dbg_printf("transplant %p\n", v->key);
681
dbe4ae98
MD
682 if (!rcu_rbtree_is_nil(v))
683 v = dup_decay_node(rbtree, v);
c479601c 684
7ba89e62
MD
685 if (rcu_rbtree_is_nil(get_parent(u))) {
686 /* pos is arbitrary for root node */
687 set_parent(v, get_parent(u), IS_RIGHT);
c479601c
MD
688 cmm_smp_wmb(); /* write into node before publish */
689 _CMM_STORE_SHARED(rbtree->root, v);
dff86257 690 } else {
7ba89e62 691 set_parent(v, get_parent(u), get_pos(u));
c479601c 692 cmm_smp_wmb(); /* write into node before publish */
7ba89e62
MD
693 if (get_pos(u) == IS_LEFT)
694 _CMM_STORE_SHARED(get_parent(u)->left, v);
806967f3 695 else
7ba89e62 696 _CMM_STORE_SHARED(get_parent(u)->right, v);
c479601c 697 }
806967f3 698
dbe4ae98 699 /* Point children to new copy (parent only used by updates/next/prev) */
c479601c 700 if (!rcu_rbtree_is_nil(v)) {
7ba89e62
MD
701 set_parent(v->right, get_decay(get_parent(v->right)),
702 get_pos(v->right));
703 set_parent(v->left, get_decay(get_parent(v->left)),
704 get_pos(v->left));
dff86257 705 }
269a9ef6 706 assert(!is_decay(rbtree->root));
dff86257
MD
707}
708
6daf6090
MD
709#else
710
711/* Non-RCU version */
712static
713void rcu_rbtree_transplant(struct rcu_rbtree *rbtree,
714 struct rcu_rbtree_node *u,
715 struct rcu_rbtree_node *v)
716{
717 dbg_printf("transplant %p\n", v->key);
718
230dd288 719 lock_test_mutex();
7ba89e62 720 if (rcu_rbtree_is_nil(get_parent(u)))
6daf6090 721 rbtree->root = v;
7ba89e62
MD
722 else if (u == get_parent(u)->left)
723 get_parent(u)->left = v;
724 else
725 get_parent(u)->right = v;
726 set_parent(v, get_parent(u), get_pos(u));
230dd288 727 unlock_test_mutex();
6daf6090
MD
728}
729
730#endif
731
dff86257
MD
732static void rcu_rbtree_remove_fixup(struct rcu_rbtree *rbtree,
733 struct rcu_rbtree_node *x)
734{
735 dbg_printf("remove fixup %p\n", x->key);
736
737 while (x != rbtree->root && x->color == COLOR_BLACK) {
7ba89e62
MD
738 assert(!is_decay(get_parent(x)));
739 assert(!is_decay(get_parent(x)->left));
740 if (x == get_parent(x)->left) {
269a9ef6 741 struct rcu_rbtree_node *w;
dff86257 742
7ba89e62 743 w = get_parent(x)->right;
dff86257
MD
744
745 if (w->color == COLOR_RED) {
269a9ef6 746 w->color = COLOR_BLACK;
7ba89e62
MD
747 get_parent(x)->color = COLOR_RED;
748 left_rotate(rbtree, get_parent(x));
269a9ef6
MD
749 x = get_decay(x);
750 assert(!is_decay(rbtree->root));
7ba89e62 751 w = get_parent(x)->right;
dff86257
MD
752 }
753 if (w->left->color == COLOR_BLACK
754 && w->right->color == COLOR_BLACK) {
755 w->color = COLOR_RED;
7ba89e62 756 x = get_parent(x);
c479601c
MD
757 assert(!is_decay(rbtree->root));
758 assert(!is_decay(x));
dff86257
MD
759 } else {
760 if (w->right->color == COLOR_BLACK) {
761 w->left->color = COLOR_BLACK;
762 w->color = COLOR_RED;
763 right_rotate(rbtree, w);
c479601c 764 assert(!is_decay(rbtree->root));
269a9ef6 765 x = get_decay(x);
7ba89e62 766 w = get_parent(x)->right;
dff86257 767 }
7ba89e62
MD
768 w->color = get_parent(x)->color;
769 get_parent(x)->color = COLOR_BLACK;
dff86257 770 w->right->color = COLOR_BLACK;
7ba89e62 771 left_rotate(rbtree, get_parent(x));
269a9ef6 772 assert(!is_decay(rbtree->root));
dff86257
MD
773 x = rbtree->root;
774 }
775 } else {
269a9ef6 776 struct rcu_rbtree_node *w;
dff86257 777
7ba89e62 778 w = get_parent(x)->left;
dff86257
MD
779
780 if (w->color == COLOR_RED) {
269a9ef6 781 w->color = COLOR_BLACK;
7ba89e62
MD
782 get_parent(x)->color = COLOR_RED;
783 right_rotate(rbtree, get_parent(x));
c479601c 784 assert(!is_decay(rbtree->root));
269a9ef6 785 x = get_decay(x);
7ba89e62 786 w = get_parent(x)->left;
dff86257
MD
787 }
788 if (w->right->color == COLOR_BLACK
789 && w->left->color == COLOR_BLACK) {
790 w->color = COLOR_RED;
7ba89e62 791 x = get_parent(x);
c479601c
MD
792 assert(!is_decay(rbtree->root));
793 assert(!is_decay(x));
dff86257
MD
794 } else {
795 if (w->left->color == COLOR_BLACK) {
796 w->right->color = COLOR_BLACK;
797 w->color = COLOR_RED;
798 left_rotate(rbtree, w);
269a9ef6
MD
799 assert(!is_decay(rbtree->root));
800 x = get_decay(x);
7ba89e62 801 w = get_parent(x)->left;
dff86257 802 }
7ba89e62
MD
803 w->color = get_parent(x)->color;
804 get_parent(x)->color = COLOR_BLACK;
dff86257 805 w->left->color = COLOR_BLACK;
7ba89e62 806 right_rotate(rbtree, get_parent(x));
c479601c 807 assert(!is_decay(rbtree->root));
dff86257
MD
808 x = rbtree->root;
809 }
810 }
811 }
812 x->color = COLOR_BLACK;
813}
814
815/*
269a9ef6
MD
816 * Delete z. All non-copied children left/right positions are unchanged.
817 */
818static
819void rcu_rbtree_remove_nonil(struct rcu_rbtree *rbtree,
820 struct rcu_rbtree_node *z,
821 struct rcu_rbtree_node *y)
dff86257 822{
269a9ef6 823 struct rcu_rbtree_node *x;
dff86257
MD
824
825 dbg_printf("remove nonil %p\n", z->key);
826 show_tree(rbtree);
827
c479601c
MD
828 assert(!is_decay(z));
829 assert(!is_decay(y));
830 assert(!is_decay(y->right));
7ba89e62 831 assert(!is_decay(get_parent(y)));
dff86257 832 x = y->right;
c479601c 833 assert(!is_decay(x));
7ba89e62 834 if (get_parent(y) == z) {
230dd288 835 y = dup_decay_node(rbtree, y);
7ba89e62 836 set_parent(x, y, get_pos(x)); /* parent for nil */
230dd288
MD
837 y->left = z->left;
838 rcu_rbtree_transplant(rbtree, z, y);
839 } else {
840 struct rcu_rbtree_node *oy_right, *z_right;
841
842 /*
843 * Need to make sure y is always visible by readers.
844 */
845 y = rcu_rbtree_min_dup_decay(rbtree, z->right, &z_right);
269a9ef6
MD
846 assert(!is_decay(y));
847 assert(!is_decay(z));
230dd288
MD
848 oy_right = y->right;
849 y->right = z_right;
7ba89e62 850 set_parent(y->right, y, IS_RIGHT);
230dd288
MD
851 assert(!is_decay(z->left));
852 y->left = z->left;
853 assert(!is_decay(oy_right));
854 rcu_rbtree_transplant(rbtree, y, oy_right);
855 rcu_rbtree_transplant(rbtree, z, y);
856 /* Update children */
857 (void) rcu_rbtree_min_update_decay(rbtree, y->right);
dff86257 858 }
c479601c 859 y = get_decay(y);
269a9ef6 860 assert(!is_decay(z));
c479601c 861 assert(!is_decay(z->left));
dff86257 862 y->color = z->color;
7ba89e62
MD
863 set_parent(y->left, y, IS_LEFT);
864 set_parent(y->right, get_decay(get_parent(y->right)), IS_RIGHT);
230dd288
MD
865 assert(!is_decay(y->left));
866 assert(!is_decay(y->right));
dff86257
MD
867}
868
869int rcu_rbtree_remove(struct rcu_rbtree *rbtree,
870 struct rcu_rbtree_node *z)
871{
872 struct rcu_rbtree_node *x, *y;
873 unsigned int y_original_color;
874
269a9ef6 875 assert(!is_decay(rbtree->root));
dff86257
MD
876 dbg_printf("remove %p\n", z->key);
877 show_tree(rbtree);
878
c479601c 879 assert(!is_decay(z));
dff86257
MD
880 y = z;
881 y_original_color = y->color;
882
883 if (rcu_rbtree_is_nil(z->left)) {
269a9ef6
MD
884 rcu_rbtree_transplant(rbtree, z, z->right);
885 assert(!is_decay(z));
c479601c 886 x = get_decay(z->right);
dff86257
MD
887 show_tree(rbtree);
888 } else if (rcu_rbtree_is_nil(z->right)) {
269a9ef6
MD
889 rcu_rbtree_transplant(rbtree, z, z->left);
890 assert(!is_decay(z));
c479601c 891 x = get_decay(z->left);
dff86257
MD
892 show_tree(rbtree);
893 } else {
894 y = rcu_rbtree_min(rbtree, z->right);
c479601c 895 assert(!is_decay(y));
dff86257 896 y_original_color = y->color;
6daf6090 897 x = y->right;
269a9ef6 898 rcu_rbtree_remove_nonil(rbtree, z, y);
6daf6090 899 x = get_decay(x);
dff86257
MD
900 show_tree(rbtree);
901 }
902 if (y_original_color == COLOR_BLACK)
903 rcu_rbtree_remove_fixup(rbtree, x);
904 show_tree(rbtree);
905 /*
906 * Commit all _CMM_STORE_SHARED().
907 */
908 cmm_smp_wmc();
909
910 return 0;
911}
This page took 0.079343 seconds and 4 git commands to generate.