Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rbtree: move augmented rbtree functionality to rbtree_augmented.h

Provide rb_insert_augmented() and rb_erase_augmented() through a new
rbtree_augmented.h include file. rb_erase_augmented() is defined there as
an __always_inline function, in order to allow inlining of augmented
rbtree callbacks into it. Since this generates a relatively large
function, each augmented rbtree user should make sure to have a single
call site.

Signed-off-by: Michel Lespinasse <walken@google.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Hillf Danton <dhillf@gmail.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Michel Lespinasse and committed by
Linus Torvalds
9c079add 147e615f

+255 -203
+13
Documentation/rbtree.txt
··· 202 202 functions with the user provided augmentation callback when inserting 203 203 and erasing nodes. 204 204 205 + C files implementing augmented rbtree manipulation must include 206 + <linux/rbtree_augmented.h> instead of <linus/rbtree.h>. Note that 207 + linux/rbtree_augmented.h exposes some rbtree implementations details 208 + you are not expected to rely on; please stick to the documented APIs 209 + there and do not include <linux/rbtree_augmented.h> from header files 210 + either so as to minimize chances of your users accidentally relying on 211 + such implementation details. 212 + 205 213 On insertion, the user must update the augmented information on the path 206 214 leading to the inserted node, then call rb_link_node() as usual and 207 215 rb_augment_inserted() instead of the usual rb_insert_color() call. ··· 234 226 - A tree rotation callback, which copies the augmented value for a given 235 227 subtree to a newly assigned subtree root AND recomputes the augmented 236 228 information for the former subtree root. 229 + 230 + The compiled code for rb_erase_augmented() may inline the propagation and 231 + copy callbacks, which results in a large function, so each augmented rbtree 232 + user should have a single rb_erase_augmented() call site in order to limit 233 + compiled code size. 237 234 238 235 239 236 Sample usage:
+1 -1
arch/x86/mm/pat_rbtree.c
··· 12 12 #include <linux/debugfs.h> 13 13 #include <linux/kernel.h> 14 14 #include <linux/module.h> 15 - #include <linux/rbtree.h> 15 + #include <linux/rbtree_augmented.h> 16 16 #include <linux/sched.h> 17 17 #include <linux/gfp.h> 18 18
+6 -2
include/linux/interval_tree_tmpl.h
··· 19 19 include/linux/interval_tree_tmpl.h 20 20 */ 21 21 22 + #include <linux/rbtree_augmented.h> 23 + 22 24 /* 23 25 * Template for implementing interval trees 24 26 * ··· 59 57 return max; 60 58 } 61 59 62 - static void IT(augment_propagate)(struct rb_node *rb, struct rb_node *stop) 60 + static inline void 61 + IT(augment_propagate)(struct rb_node *rb, struct rb_node *stop) 63 62 { 64 63 while (rb != stop) { 65 64 ITSTRUCT *node = rb_entry(rb, ITSTRUCT, ITRB); ··· 72 69 } 73 70 } 74 71 75 - static void IT(augment_copy)(struct rb_node *rb_old, struct rb_node *rb_new) 72 + static inline void 73 + IT(augment_copy)(struct rb_node *rb_old, struct rb_node *rb_new) 76 74 { 77 75 ITSTRUCT *old = rb_entry(rb_old, ITSTRUCT, ITRB); 78 76 ITSTRUCT *new = rb_entry(rb_new, ITSTRUCT, ITRB);
-48
include/linux/rbtree.h
··· 62 62 extern void rb_erase(struct rb_node *, struct rb_root *); 63 63 64 64 65 - struct rb_augment_callbacks { 66 - void (*propagate)(struct rb_node *node, struct rb_node *stop); 67 - void (*copy)(struct rb_node *old, struct rb_node *new); 68 - void (*rotate)(struct rb_node *old, struct rb_node *new); 69 - }; 70 - 71 - extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, 72 - void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); 73 - extern void rb_erase_augmented(struct rb_node *node, struct rb_root *root, 74 - const struct rb_augment_callbacks *augment); 75 - static inline void 76 - rb_insert_augmented(struct rb_node *node, struct rb_root *root, 77 - const struct rb_augment_callbacks *augment) 78 - { 79 - __rb_insert_augmented(node, root, augment->rotate); 80 - } 81 - 82 - #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \ 83 - rbtype, rbaugmented, rbcompute) \ 84 - static void rbname ## _propagate(struct rb_node *rb, struct rb_node *stop) \ 85 - { \ 86 - while (rb != stop) { \ 87 - rbstruct *node = rb_entry(rb, rbstruct, rbfield); \ 88 - rbtype augmented = rbcompute(node); \ 89 - if (node->rbaugmented == augmented) \ 90 - break; \ 91 - node->rbaugmented = augmented; \ 92 - rb = rb_parent(&node->rbfield); \ 93 - } \ 94 - } \ 95 - static void rbname ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ 96 - { \ 97 - rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ 98 - rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ 99 - new->rbaugmented = old->rbaugmented; \ 100 - } \ 101 - static void rbname ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ 102 - { \ 103 - rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ 104 - rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ 105 - new->rbaugmented = old->rbaugmented; \ 106 - old->rbaugmented = rbcompute(old); \ 107 - } \ 108 - rbstatic const struct rb_augment_callbacks rbname = { \ 109 - rbname ## _propagate, rbname ## _copy, rbname ## _rotate \ 110 - }; 111 - 112 - 113 65 /* Find logical next and previous nodes in a tree */ 114 66 extern struct rb_node *rb_next(const struct rb_node *); 115 67 extern struct rb_node *rb_prev(const struct rb_node *);
+223
include/linux/rbtree_augmented.h
··· 1 + /* 2 + Red Black Trees 3 + (C) 1999 Andrea Arcangeli <andrea@suse.de> 4 + (C) 2002 David Woodhouse <dwmw2@infradead.org> 5 + (C) 2012 Michel Lespinasse <walken@google.com> 6 + 7 + This program is free software; you can redistribute it and/or modify 8 + it under the terms of the GNU General Public License as published by 9 + the Free Software Foundation; either version 2 of the License, or 10 + (at your option) any later version. 11 + 12 + This program is distributed in the hope that it will be useful, 13 + but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + GNU General Public License for more details. 16 + 17 + You should have received a copy of the GNU General Public License 18 + along with this program; if not, write to the Free Software 19 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 + 21 + linux/include/linux/rbtree_augmented.h 22 + */ 23 + 24 + #ifndef _LINUX_RBTREE_AUGMENTED_H 25 + #define _LINUX_RBTREE_AUGMENTED_H 26 + 27 + #include <linux/rbtree.h> 28 + 29 + /* 30 + * Please note - only struct rb_augment_callbacks and the prototypes for 31 + * rb_insert_augmented() and rb_erase_augmented() are intended to be public. 32 + * The rest are implementation details you are not expected to depend on. 33 + * 34 + * See Documentation/rbtree.txt for documentation and samples. 35 + */ 36 + 37 + struct rb_augment_callbacks { 38 + void (*propagate)(struct rb_node *node, struct rb_node *stop); 39 + void (*copy)(struct rb_node *old, struct rb_node *new); 40 + void (*rotate)(struct rb_node *old, struct rb_node *new); 41 + }; 42 + 43 + extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, 44 + void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); 45 + static inline void 46 + rb_insert_augmented(struct rb_node *node, struct rb_root *root, 47 + const struct rb_augment_callbacks *augment) 48 + { 49 + __rb_insert_augmented(node, root, augment->rotate); 50 + } 51 + 52 + #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \ 53 + rbtype, rbaugmented, rbcompute) \ 54 + static inline void \ 55 + rbname ## _propagate(struct rb_node *rb, struct rb_node *stop) \ 56 + { \ 57 + while (rb != stop) { \ 58 + rbstruct *node = rb_entry(rb, rbstruct, rbfield); \ 59 + rbtype augmented = rbcompute(node); \ 60 + if (node->rbaugmented == augmented) \ 61 + break; \ 62 + node->rbaugmented = augmented; \ 63 + rb = rb_parent(&node->rbfield); \ 64 + } \ 65 + } \ 66 + static inline void \ 67 + rbname ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ 68 + { \ 69 + rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ 70 + rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ 71 + new->rbaugmented = old->rbaugmented; \ 72 + } \ 73 + static void \ 74 + rbname ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ 75 + { \ 76 + rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ 77 + rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ 78 + new->rbaugmented = old->rbaugmented; \ 79 + old->rbaugmented = rbcompute(old); \ 80 + } \ 81 + rbstatic const struct rb_augment_callbacks rbname = { \ 82 + rbname ## _propagate, rbname ## _copy, rbname ## _rotate \ 83 + }; 84 + 85 + 86 + #define RB_RED 0 87 + #define RB_BLACK 1 88 + 89 + #define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) 90 + 91 + #define __rb_color(pc) ((pc) & 1) 92 + #define __rb_is_black(pc) __rb_color(pc) 93 + #define __rb_is_red(pc) (!__rb_color(pc)) 94 + #define rb_color(rb) __rb_color((rb)->__rb_parent_color) 95 + #define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color) 96 + #define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) 97 + 98 + static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) 99 + { 100 + rb->__rb_parent_color = rb_color(rb) | (unsigned long)p; 101 + } 102 + 103 + static inline void rb_set_parent_color(struct rb_node *rb, 104 + struct rb_node *p, int color) 105 + { 106 + rb->__rb_parent_color = (unsigned long)p | color; 107 + } 108 + 109 + static inline void 110 + __rb_change_child(struct rb_node *old, struct rb_node *new, 111 + struct rb_node *parent, struct rb_root *root) 112 + { 113 + if (parent) { 114 + if (parent->rb_left == old) 115 + parent->rb_left = new; 116 + else 117 + parent->rb_right = new; 118 + } else 119 + root->rb_node = new; 120 + } 121 + 122 + extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, 123 + void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); 124 + 125 + static __always_inline void 126 + rb_erase_augmented(struct rb_node *node, struct rb_root *root, 127 + const struct rb_augment_callbacks *augment) 128 + { 129 + struct rb_node *child = node->rb_right, *tmp = node->rb_left; 130 + struct rb_node *parent, *rebalance; 131 + unsigned long pc; 132 + 133 + if (!tmp) { 134 + /* 135 + * Case 1: node to erase has no more than 1 child (easy!) 136 + * 137 + * Note that if there is one child it must be red due to 5) 138 + * and node must be black due to 4). We adjust colors locally 139 + * so as to bypass __rb_erase_color() later on. 140 + */ 141 + pc = node->__rb_parent_color; 142 + parent = __rb_parent(pc); 143 + __rb_change_child(node, child, parent, root); 144 + if (child) { 145 + child->__rb_parent_color = pc; 146 + rebalance = NULL; 147 + } else 148 + rebalance = __rb_is_black(pc) ? parent : NULL; 149 + tmp = parent; 150 + } else if (!child) { 151 + /* Still case 1, but this time the child is node->rb_left */ 152 + tmp->__rb_parent_color = pc = node->__rb_parent_color; 153 + parent = __rb_parent(pc); 154 + __rb_change_child(node, tmp, parent, root); 155 + rebalance = NULL; 156 + tmp = parent; 157 + } else { 158 + struct rb_node *successor = child, *child2; 159 + tmp = child->rb_left; 160 + if (!tmp) { 161 + /* 162 + * Case 2: node's successor is its right child 163 + * 164 + * (n) (s) 165 + * / \ / \ 166 + * (x) (s) -> (x) (c) 167 + * \ 168 + * (c) 169 + */ 170 + parent = successor; 171 + child2 = successor->rb_right; 172 + augment->copy(node, successor); 173 + } else { 174 + /* 175 + * Case 3: node's successor is leftmost under 176 + * node's right child subtree 177 + * 178 + * (n) (s) 179 + * / \ / \ 180 + * (x) (y) -> (x) (y) 181 + * / / 182 + * (p) (p) 183 + * / / 184 + * (s) (c) 185 + * \ 186 + * (c) 187 + */ 188 + do { 189 + parent = successor; 190 + successor = tmp; 191 + tmp = tmp->rb_left; 192 + } while (tmp); 193 + parent->rb_left = child2 = successor->rb_right; 194 + successor->rb_right = child; 195 + rb_set_parent(child, successor); 196 + augment->copy(node, successor); 197 + augment->propagate(parent, successor); 198 + } 199 + 200 + successor->rb_left = tmp = node->rb_left; 201 + rb_set_parent(tmp, successor); 202 + 203 + pc = node->__rb_parent_color; 204 + tmp = __rb_parent(pc); 205 + __rb_change_child(node, successor, tmp, root); 206 + if (child2) { 207 + successor->__rb_parent_color = pc; 208 + rb_set_parent_color(child2, parent, RB_BLACK); 209 + rebalance = NULL; 210 + } else { 211 + unsigned long pc2 = successor->__rb_parent_color; 212 + successor->__rb_parent_color = pc; 213 + rebalance = __rb_is_black(pc2) ? parent : NULL; 214 + } 215 + tmp = successor; 216 + } 217 + 218 + augment->propagate(tmp, NULL); 219 + if (rebalance) 220 + __rb_erase_color(rebalance, root, augment->rotate); 221 + } 222 + 223 + #endif /* _LINUX_RBTREE_AUGMENTED_H */
+11 -151
lib/rbtree.c
··· 21 21 linux/lib/rbtree.c 22 22 */ 23 23 24 - #include <linux/rbtree.h> 24 + #include <linux/rbtree_augmented.h> 25 25 #include <linux/export.h> 26 26 27 27 /* ··· 44 44 * parentheses and have some accompanying text comment. 45 45 */ 46 46 47 - #define RB_RED 0 48 - #define RB_BLACK 1 49 - 50 - #define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) 51 - 52 - #define __rb_color(pc) ((pc) & 1) 53 - #define __rb_is_black(pc) __rb_color(pc) 54 - #define __rb_is_red(pc) (!__rb_color(pc)) 55 - #define rb_color(rb) __rb_color((rb)->__rb_parent_color) 56 - #define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color) 57 - #define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) 58 - 59 47 static inline void rb_set_black(struct rb_node *rb) 60 48 { 61 49 rb->__rb_parent_color |= RB_BLACK; 62 50 } 63 51 64 - static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) 65 - { 66 - rb->__rb_parent_color = rb_color(rb) | (unsigned long)p; 67 - } 68 - 69 - static inline void rb_set_parent_color(struct rb_node *rb, 70 - struct rb_node *p, int color) 71 - { 72 - rb->__rb_parent_color = (unsigned long)p | color; 73 - } 74 - 75 52 static inline struct rb_node *rb_red_parent(struct rb_node *red) 76 53 { 77 54 return (struct rb_node *)red->__rb_parent_color; 78 - } 79 - 80 - static inline void 81 - __rb_change_child(struct rb_node *old, struct rb_node *new, 82 - struct rb_node *parent, struct rb_root *root) 83 - { 84 - if (parent) { 85 - if (parent->rb_left == old) 86 - parent->rb_left = new; 87 - else 88 - parent->rb_right = new; 89 - } else 90 - root->rb_node = new; 91 55 } 92 56 93 57 /* ··· 194 230 } 195 231 } 196 232 197 - static __always_inline void 233 + __always_inline void 198 234 __rb_erase_color(struct rb_node *parent, struct rb_root *root, 199 - const struct rb_augment_callbacks *augment) 235 + void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) 200 236 { 201 237 struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; 202 238 ··· 225 261 rb_set_parent_color(tmp1, parent, RB_BLACK); 226 262 __rb_rotate_set_parents(parent, sibling, root, 227 263 RB_RED); 228 - augment->rotate(parent, sibling); 264 + augment_rotate(parent, sibling); 229 265 sibling = tmp1; 230 266 } 231 267 tmp1 = sibling->rb_right; ··· 277 313 if (tmp1) 278 314 rb_set_parent_color(tmp1, sibling, 279 315 RB_BLACK); 280 - augment->rotate(sibling, tmp2); 316 + augment_rotate(sibling, tmp2); 281 317 tmp1 = sibling; 282 318 sibling = tmp2; 283 319 } ··· 300 336 rb_set_parent(tmp2, parent); 301 337 __rb_rotate_set_parents(parent, sibling, root, 302 338 RB_BLACK); 303 - augment->rotate(parent, sibling); 339 + augment_rotate(parent, sibling); 304 340 break; 305 341 } else { 306 342 sibling = parent->rb_left; ··· 311 347 rb_set_parent_color(tmp1, parent, RB_BLACK); 312 348 __rb_rotate_set_parents(parent, sibling, root, 313 349 RB_RED); 314 - augment->rotate(parent, sibling); 350 + augment_rotate(parent, sibling); 315 351 sibling = tmp1; 316 352 } 317 353 tmp1 = sibling->rb_left; ··· 338 374 if (tmp1) 339 375 rb_set_parent_color(tmp1, sibling, 340 376 RB_BLACK); 341 - augment->rotate(sibling, tmp2); 377 + augment_rotate(sibling, tmp2); 342 378 tmp1 = sibling; 343 379 sibling = tmp2; 344 380 } ··· 350 386 rb_set_parent(tmp2, parent); 351 387 __rb_rotate_set_parents(parent, sibling, root, 352 388 RB_BLACK); 353 - augment->rotate(parent, sibling); 389 + augment_rotate(parent, sibling); 354 390 break; 355 391 } 356 392 } 357 393 } 358 - 359 - static __always_inline void 360 - __rb_erase(struct rb_node *node, struct rb_root *root, 361 - const struct rb_augment_callbacks *augment) 362 - { 363 - struct rb_node *child = node->rb_right, *tmp = node->rb_left; 364 - struct rb_node *parent, *rebalance; 365 - unsigned long pc; 366 - 367 - if (!tmp) { 368 - /* 369 - * Case 1: node to erase has no more than 1 child (easy!) 370 - * 371 - * Note that if there is one child it must be red due to 5) 372 - * and node must be black due to 4). We adjust colors locally 373 - * so as to bypass __rb_erase_color() later on. 374 - */ 375 - pc = node->__rb_parent_color; 376 - parent = __rb_parent(pc); 377 - __rb_change_child(node, child, parent, root); 378 - if (child) { 379 - child->__rb_parent_color = pc; 380 - rebalance = NULL; 381 - } else 382 - rebalance = __rb_is_black(pc) ? parent : NULL; 383 - tmp = parent; 384 - } else if (!child) { 385 - /* Still case 1, but this time the child is node->rb_left */ 386 - tmp->__rb_parent_color = pc = node->__rb_parent_color; 387 - parent = __rb_parent(pc); 388 - __rb_change_child(node, tmp, parent, root); 389 - rebalance = NULL; 390 - tmp = parent; 391 - } else { 392 - struct rb_node *successor = child, *child2; 393 - tmp = child->rb_left; 394 - if (!tmp) { 395 - /* 396 - * Case 2: node's successor is its right child 397 - * 398 - * (n) (s) 399 - * / \ / \ 400 - * (x) (s) -> (x) (c) 401 - * \ 402 - * (c) 403 - */ 404 - parent = successor; 405 - child2 = successor->rb_right; 406 - augment->copy(node, successor); 407 - } else { 408 - /* 409 - * Case 3: node's successor is leftmost under 410 - * node's right child subtree 411 - * 412 - * (n) (s) 413 - * / \ / \ 414 - * (x) (y) -> (x) (y) 415 - * / / 416 - * (p) (p) 417 - * / / 418 - * (s) (c) 419 - * \ 420 - * (c) 421 - */ 422 - do { 423 - parent = successor; 424 - successor = tmp; 425 - tmp = tmp->rb_left; 426 - } while (tmp); 427 - parent->rb_left = child2 = successor->rb_right; 428 - successor->rb_right = child; 429 - rb_set_parent(child, successor); 430 - augment->copy(node, successor); 431 - augment->propagate(parent, successor); 432 - } 433 - 434 - successor->rb_left = tmp = node->rb_left; 435 - rb_set_parent(tmp, successor); 436 - 437 - pc = node->__rb_parent_color; 438 - tmp = __rb_parent(pc); 439 - __rb_change_child(node, successor, tmp, root); 440 - if (child2) { 441 - successor->__rb_parent_color = pc; 442 - rb_set_parent_color(child2, parent, RB_BLACK); 443 - rebalance = NULL; 444 - } else { 445 - unsigned long pc2 = successor->__rb_parent_color; 446 - successor->__rb_parent_color = pc; 447 - rebalance = __rb_is_black(pc2) ? parent : NULL; 448 - } 449 - tmp = successor; 450 - } 451 - 452 - augment->propagate(tmp, NULL); 453 - if (rebalance) 454 - __rb_erase_color(rebalance, root, augment); 455 - } 394 + EXPORT_SYMBOL(__rb_erase_color); 456 395 457 396 /* 458 397 * Non-augmented rbtree manipulation functions. ··· 380 513 381 514 void rb_erase(struct rb_node *node, struct rb_root *root) 382 515 { 383 - __rb_erase(node, root, &dummy_callbacks); 516 + rb_erase_augmented(node, root, &dummy_callbacks); 384 517 } 385 518 EXPORT_SYMBOL(rb_erase); 386 519 ··· 397 530 __rb_insert(node, root, augment_rotate); 398 531 } 399 532 EXPORT_SYMBOL(__rb_insert_augmented); 400 - 401 - void rb_erase_augmented(struct rb_node *node, struct rb_root *root, 402 - const struct rb_augment_callbacks *augment) 403 - { 404 - __rb_erase(node, root, augment); 405 - } 406 - EXPORT_SYMBOL(rb_erase_augmented); 407 533 408 534 /* 409 535 * This function returns the first node (in sort order) of the tree.
+1 -1
lib/rbtree_test.c
··· 1 1 #include <linux/module.h> 2 - #include <linux/rbtree.h> 2 + #include <linux/rbtree_augmented.h> 3 3 #include <linux/random.h> 4 4 #include <asm/timex.h> 5 5