diff --git a/sys/sys/tree.h b/sys/sys/tree.h index 971562a5c121..74f1f23d3576 100644 --- a/sys/sys/tree.h +++ b/sys/sys/tree.h @@ -410,12 +410,17 @@ struct { \ RB_SET_PARENT(elm, tmp, field); \ } while (/*CONSTCOND*/ 0) +#if defined(_KERNEL) && defined(DIAGNOSTIC) && !defined(_RB_DIAGNOSTIC) +#define _RB_DIAGNOSTIC 1 +#endif + /* Generates prototypes and inline functions */ #define RB_PROTOTYPE(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) #define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) #define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ + RB_PROTOTYPE_RANK(name, type, attr) \ RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \ RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \ RB_PROTOTYPE_INSERT(name, type, attr); \ @@ -426,6 +431,12 @@ struct { \ RB_PROTOTYPE_PREV(name, type, attr); \ RB_PROTOTYPE_MINMAX(name, type, attr); \ RB_PROTOTYPE_REINSERT(name, type, attr); +#ifdef _RB_DIAGNOSTIC +#define RB_PROTOTYPE_RANK(name, type, attr) \ + attr int name##_RB_RANK(struct type *); +#else +#define RB_PROTOTYPE_RANK(name, type, attr) +#endif #define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \ attr void name##_RB_INSERT_COLOR(struct name *, struct type *) #define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \ @@ -456,6 +467,7 @@ struct { \ #define RB_GENERATE_STATIC(name, type, field, cmp) \ RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ + RB_GENERATE_RANK(name, type, field, attr) \ RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ RB_GENERATE_INSERT(name, type, field, cmp, attr) \ @@ -467,6 +479,31 @@ struct { \ RB_GENERATE_MINMAX(name, type, field, attr) \ RB_GENERATE_REINSERT(name, type, field, cmp, attr) +#ifdef _RB_DIAGNOSTIC +#define RB_GENERATE_RANK(name, type, field, attr) \ +attr int \ +name##_RB_RANK(struct type *elm) \ +{ \ + struct type *left, *right; \ + int left_rank, right_rank; \ + __uintptr_t bits; \ + \ + if (elm == NULL) \ + return (0); \ + bits = RB_BITS(elm, field); \ + left = RB_LEFT(elm, field); \ + left_rank = ((bits & RB_RED_L) ? 2 : 1) + name##_RB_RANK(left); \ + right = RB_RIGHT(elm, field); \ + right_rank = ((bits & RB_RED_R) ? 2 : 1) + name##_RB_RANK(right); \ + if (left_rank != right_rank || \ + (left_rank == 2 && left == NULL && right == NULL)) \ + return (-1); \ + return (left_rank); \ +} +#else +#define RB_GENERATE_RANK(name, type, field, attr) +#endif + #define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ attr void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ diff --git a/tests/sys/sys/rb_test.c b/tests/sys/sys/rb_test.c index c558ad6098cf..149fbe052bde 100644 --- a/tests/sys/sys/rb_test.c +++ b/tests/sys/sys/rb_test.c @@ -29,6 +29,7 @@ */ #include +#define _RB_DIAGNOSTIC 1 #include #include @@ -54,52 +55,54 @@ RB_PROTOTYPE(tree, node, node, compare); RB_GENERATE(tree, node, node, compare); #define ITER 150 -#define MIN 5 -#define MAX 5000 ATF_TC_WITHOUT_HEAD(rb_test); ATF_TC_BODY(rb_test, tc) { - struct node *tmp, *ins; - int i, max, min; + struct node *tmp, *ins, store[ITER]; + int i, j, k, max, min; - max = min = 42; /* pacify gcc */ + min = ITER; + max = -1; RB_INIT(&root); + /* Initialize keys */ + for (i = 0; i < ITER; i++) + store[i].key = i; + + /* Randomly shuffle keys */ for (i = 0; i < ITER; i++) { - tmp = malloc(sizeof(struct node)); - ATF_REQUIRE_MSG(tmp != NULL, "malloc failed"); - do { - tmp->key = arc4random_uniform(MAX-MIN); - tmp->key += MIN; - } while (RB_FIND(tree, &root, tmp) != NULL); - if (i == 0) - max = min = tmp->key; - else { - if (tmp->key > max) - max = tmp->key; - if (tmp->key < min) - min = tmp->key; - } - ATF_REQUIRE_EQ(NULL, RB_INSERT(tree, &root, tmp)); + j = i + arc4random_uniform(ITER - i); + k = store[j].key; + store[j].key = store[i].key; + store[i].key = k; } - ins = RB_MIN(tree, &root); - ATF_REQUIRE_MSG(ins != NULL, "RB_MIN error"); - ATF_CHECK_EQ(min, ins->key); - tmp = ins; - ins = RB_MAX(tree, &root); - ATF_REQUIRE_MSG(ins != NULL, "RB_MAX error"); - ATF_CHECK_EQ(max, ins->key); - - ATF_CHECK_EQ(tmp, RB_REMOVE(tree, &root, tmp)); - - for (i = 0; i < ITER - 1; i++) { + for (i = 0; i < ITER; i++) { + for (j = 0; j < i; ++j) { + tmp = &store[j]; + ATF_REQUIRE_EQ(tmp, RB_FIND(tree, &root, tmp)); + } + tmp = &store[i]; + if (tmp->key > max) + max = tmp->key; + if (tmp->key < min) + min = tmp->key; + ATF_REQUIRE_EQ(NULL, RB_INSERT(tree, &root, tmp)); + ins = RB_MIN(tree, &root); + ATF_REQUIRE_MSG(ins != NULL, "RB_MIN error"); + ATF_CHECK_EQ(min, ins->key); + ins = RB_MAX(tree, &root); + ATF_REQUIRE_MSG(ins != NULL, "RB_MAX error"); + ATF_CHECK_EQ(max, ins->key); + } + tmp = RB_ROOT(&root); + ATF_REQUIRE_MSG(tree_RB_RANK(tmp) >= 0, "RB rank balance error"); + for (i = 0; i < ITER; i++) { tmp = RB_ROOT(&root); ATF_REQUIRE_MSG(tmp != NULL, "RB_ROOT error"); ATF_CHECK_EQ(tmp, RB_REMOVE(tree, &root, tmp)); - free(tmp); } }