From 95ce90253416a118fdd72592fd737e7108acb718 Mon Sep 17 00:00:00 2001 From: Stanislav Paskalev Date: Mon, 9 Oct 2023 15:47:49 +0300 Subject: [PATCH] Make buddy_walk iterate free slots as well (#88) --- buddy_alloc.h | 72 ++++++++++++++++++++++++++------------------------- tests.c | 20 +++++++++----- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/buddy_alloc.h b/buddy_alloc.h index 72cfa8d..f725463 100644 --- a/buddy_alloc.h +++ b/buddy_alloc.h @@ -119,14 +119,14 @@ void buddy_unsafe_release_range(struct buddy *buddy, void *ptr, size_t requested */ /* - * Iterate through the allocated slots and call the provided function for each of them. + * Iterate through the free and allocated slots and call the provided function for each of them. * * If the provided function returns a non-NULL result the iteration stops and the result * is returned to called. NULL is returned upon completing iteration without stopping. * * The iteration order is implementation-defined and may change between versions. */ -void *buddy_walk(struct buddy *buddy, void *(fp)(void *ctx, void *addr, size_t slot_size), void *ctx); +void *buddy_walk(struct buddy *buddy, void *(fp)(void *ctx, void *addr, size_t slot_size, size_t allocated), void *ctx); /* * Miscellaneous functions @@ -859,12 +859,15 @@ void buddy_unsafe_release_range(struct buddy *buddy, void *ptr, size_t requested } void *buddy_walk(struct buddy *buddy, - void *(fp)(void *ctx, void *addr, size_t slot_size), void *ctx) { + void *(fp)(void *ctx, void *addr, size_t slot_size, size_t allocated), + void *ctx) { unsigned char *main; size_t effective_memory_size, tree_order, pos_status, pos_size; struct buddy_tree *tree; unsigned char *addr; struct buddy_tree_walk_state state; + struct buddy_tree_pos test_pos; + void *callback_result; if (buddy == NULL) { return NULL; @@ -880,42 +883,41 @@ void *buddy_walk(struct buddy *buddy, state = buddy_tree_walk_state_root(); do { pos_status = buddy_tree_status(tree, state.current_pos); - if (pos_status == 0) { /* Empty position */ - state.going_up = 1; - } else if (pos_status != (tree_order - state.current_pos.depth + 1)) { /* Partially-allocated */ + if (pos_status != (tree_order - state.current_pos.depth + 1)) { /* Partially-allocated */ + continue; + } + + /* + * The tree doesn't make a distinction of a fully-allocated node + * due to a single allocation and a fully-allocated due to maxed out + * child allocations - we need to check the children. + * A child-allocated node will have both children set to their maximum + * but it is sufficient to check just one for non-zero. + */ + test_pos = buddy_tree_left_child(state.current_pos); + if (buddy_tree_valid(tree, test_pos) && buddy_tree_status(tree, test_pos)) { continue; - } else { /* Fully-allocated */ + } + + /* Current node is free or allocated, process */ + pos_size = effective_memory_size >> (state.current_pos.depth - 1u); + addr = address_for_position(buddy, state.current_pos); + if (((size_t)(addr - main) + pos_size) > buddy->memory_size) { /* - * The tree doesn't make a distinction of a fully-allocated node - * due to a single allocation and a fully-allocated due to maxed out - * child allocations - we need to check the children. - * A child-allocated node will have both children set to their maximum - * but it is sufficient to check just one for non-zero. + * Do not process virtual slots + * As virtual slots are on the right side of the tree + * if we see a one with the current iteration order this + * means that all subsequent slots will be virtual, + * hence we can return early. */ - struct buddy_tree_pos left = buddy_tree_left_child(state.current_pos); - if (buddy_tree_valid(tree, left) && buddy_tree_status(tree, left)) { - continue; - } - - /* Current node is allocated, process */ - pos_size = effective_memory_size >> (state.current_pos.depth - 1u); - addr = address_for_position(buddy, state.current_pos); - if (((size_t)(addr - main) + pos_size) > buddy->memory_size) { - /* - * Do not process virtual slots - * As virtual slots are on the right side of the tree - * if we see a one with the current iteration order this - * means that all subsequent slots will be virtual, - * hence we can return early. - */ - return NULL; - } else { - void *result = (fp)(ctx, addr, pos_size); - if (result != NULL) { - return result; - } - } + return NULL; + } + callback_result = (fp)(ctx, addr, pos_size, pos_status > 0); + if (callback_result != NULL) { + return callback_result; } + state.going_up = 1; + } while (buddy_tree_walk(tree, &state)); return NULL; } diff --git a/tests.c b/tests.c index c725325..f2d4ca9 100644 --- a/tests.c +++ b/tests.c @@ -1438,10 +1438,11 @@ void test_buddy_large_arena(void) { free(data_buf); } -void *walker_01(void *ctx, void *addr, size_t size) { +void *walker_01(void *ctx, void *addr, size_t size, size_t allocated) { size_t *counter = (size_t *) ctx; (void) addr; assert(size == 64); + assert(allocated); (*counter)++; if ((*counter) > 2) { return addr; /* cause a stop */ @@ -1476,10 +1477,11 @@ void test_buddy_walk_01(void) { free(buddy_buf); } -void *walker_02(void *ctx, void *addr, size_t size) { +void *walker_02(void *ctx, void *addr, size_t size, size_t allocated) { size_t *counter = (size_t *) ctx; (void) addr; assert(size == 128); + assert(allocated); (*counter)++; if ((*counter) > 2) { return addr; /* cause a stop */ @@ -1506,7 +1508,7 @@ struct walker_03_entry { size_t size; }; -void *walker_03(void *ctx, void *addr, size_t size) { +void *walker_03(void *ctx, void *addr, size_t size, size_t allocated) { struct walker_03_entry (*context) = (struct walker_03_entry *) ctx; unsigned int found = 0; for (size_t i = 0; i < 3; i++) { @@ -1517,6 +1519,7 @@ void *walker_03(void *ctx, void *addr, size_t size) { } } assert(found); + (void) allocated; return NULL; } @@ -1534,10 +1537,11 @@ void test_buddy_walk_03(void) { free(buddy_buf); } -void *walker_04(void *ctx, void *addr, size_t size) { +void *walker_04(void *ctx, void *addr, size_t size, size_t allocated) { struct buddy *buddy = (struct buddy *) ctx; assert(addr != NULL); assert(size != 0); + assert(allocated); buddy_free(buddy, addr); return NULL; } @@ -1556,9 +1560,10 @@ void test_buddy_walk_04(void) { free(buddy_buf); } -void *walker_05(void *ctx, void *addr, size_t size) { +void *walker_05(void *ctx, void *addr, size_t size, size_t allocated) { (void) addr; (void) size; + (void) allocated; return ctx; } @@ -1570,12 +1575,13 @@ void test_buddy_walk_05(void) { start_test; buddy = buddy_init(buddy_buf, data_buf, 3648); // virtual slots assert(buddy_walk(buddy, walker_05, &ctx) == NULL); - assert(walker_05(&ctx, NULL, 0) == &ctx); // coverage + assert(walker_05(&ctx, NULL, 0, 1) == &ctx); // coverage free(buddy_buf); } -void *walker_06(void *ctx, void *addr, size_t size) { +void *walker_06(void *ctx, void *addr, size_t size, size_t allocated) { struct buddy *buddy = (struct buddy *) ctx; + assert(allocated); buddy_realloc(buddy, addr, size); return NULL; }