Skip to content

Commit

Permalink
Make buddy_walk iterate free slots as well (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
spaskalev authored Oct 9, 2023
1 parent aef103c commit 95ce902
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 42 deletions.
72 changes: 37 additions & 35 deletions buddy_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
20 changes: 13 additions & 7 deletions tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand All @@ -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++) {
Expand All @@ -1517,6 +1519,7 @@ void *walker_03(void *ctx, void *addr, size_t size) {
}
}
assert(found);
(void) allocated;
return NULL;
}

Expand All @@ -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;
}
Expand All @@ -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;
}

Expand All @@ -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;
}
Expand Down

0 comments on commit 95ce902

Please sign in to comment.