Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make buddy_walk iterate free slots as well #88

Merged
merged 1 commit into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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