diff options
-rw-r--r-- | lib/rbtree.c | 28 | ||||
-rw-r--r-- | tools/perf/util/include/linux/rbtree.h | 1 |
2 files changed, 18 insertions, 11 deletions
diff --git a/lib/rbtree.c b/lib/rbtree.c index 41cf19b2fe5..baf7c835c57 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c | |||
@@ -259,10 +259,22 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, | |||
259 | { | 259 | { |
260 | struct rb_node *other; | 260 | struct rb_node *other; |
261 | 261 | ||
262 | while ((!node || rb_is_black(node)) && node != root->rb_node) | 262 | while (true) { |
263 | { | 263 | /* |
264 | if (parent->rb_left == node) | 264 | * Loop invariant: all leaf paths going through node have a |
265 | { | 265 | * black node count that is 1 lower than other leaf paths. |
266 | * | ||
267 | * If node is red, we can flip it to black to adjust. | ||
268 | * If node is the root, all leaf paths go through it. | ||
269 | * Otherwise, we need to adjust the tree through color flips | ||
270 | * and tree rotations as per one of the 4 cases below. | ||
271 | */ | ||
272 | if (node && rb_is_red(node)) { | ||
273 | rb_set_black(node); | ||
274 | break; | ||
275 | } else if (!parent) { | ||
276 | break; | ||
277 | } else if (parent->rb_left == node) { | ||
266 | other = parent->rb_right; | 278 | other = parent->rb_right; |
267 | if (rb_is_red(other)) | 279 | if (rb_is_red(other)) |
268 | { | 280 | { |
@@ -291,12 +303,9 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, | |||
291 | rb_set_black(parent); | 303 | rb_set_black(parent); |
292 | rb_set_black(other->rb_right); | 304 | rb_set_black(other->rb_right); |
293 | __rb_rotate_left(parent, root); | 305 | __rb_rotate_left(parent, root); |
294 | node = root->rb_node; | ||
295 | break; | 306 | break; |
296 | } | 307 | } |
297 | } | 308 | } else { |
298 | else | ||
299 | { | ||
300 | other = parent->rb_left; | 309 | other = parent->rb_left; |
301 | if (rb_is_red(other)) | 310 | if (rb_is_red(other)) |
302 | { | 311 | { |
@@ -325,13 +334,10 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, | |||
325 | rb_set_black(parent); | 334 | rb_set_black(parent); |
326 | rb_set_black(other->rb_left); | 335 | rb_set_black(other->rb_left); |
327 | __rb_rotate_right(parent, root); | 336 | __rb_rotate_right(parent, root); |
328 | node = root->rb_node; | ||
329 | break; | 337 | break; |
330 | } | 338 | } |
331 | } | 339 | } |
332 | } | 340 | } |
333 | if (node) | ||
334 | rb_set_black(node); | ||
335 | } | 341 | } |
336 | 342 | ||
337 | void rb_erase(struct rb_node *node, struct rb_root *root) | 343 | void rb_erase(struct rb_node *node, struct rb_root *root) |
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h index 2a030c5af3a..9bcdc844b33 100644 --- a/tools/perf/util/include/linux/rbtree.h +++ b/tools/perf/util/include/linux/rbtree.h | |||
@@ -1,2 +1,3 @@ | |||
1 | #include <stdbool.h> | 1 | #include <stdbool.h> |
2 | #include <stdbool.h> | ||
2 | #include "../../../../include/linux/rbtree.h" | 3 | #include "../../../../include/linux/rbtree.h" |