Simplify buddy_startup and remove buddy_cleanup
This commit is contained in:
@@ -215,7 +215,7 @@
|
|||||||
* 4 256
|
* 4 256
|
||||||
* 5 256
|
* 5 256
|
||||||
* 6 256
|
* 6 256
|
||||||
* 7 256
|
* 7 256
|
||||||
*
|
*
|
||||||
* The group of bits of a block are stored breadth first,
|
* The group of bits of a block are stored breadth first,
|
||||||
* while the groups themselves are stored linearly.
|
* while the groups themselves are stored linearly.
|
||||||
@@ -270,6 +270,42 @@
|
|||||||
|
|
||||||
#include "buddy.h"
|
#include "buddy.h"
|
||||||
|
|
||||||
|
#define BUDDY_ALLOC_NUM_LISTS (BUDDY_ALLOC_MAX_BLOCK_LOG2 - BUDDY_ALLOC_MIN_BLOCK_LOG2 + 1)
|
||||||
|
#define BUDDY_ALLOC_MAX_BLOCK_SIZE (1U << BUDDY_ALLOC_MAX_BLOCK_LOG2)
|
||||||
|
#define BUDDY_ALLOC_MIN_BLOCK_SIZE (1U << BUDDY_ALLOC_MIN_BLOCK_LOG2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To keep track of the allocation state of a page,
|
||||||
|
* we need one bit for each possible block that can
|
||||||
|
* be made out of it. For instance, if the page can
|
||||||
|
* only be allocated in its entirety, 1 bit is required.
|
||||||
|
* If the blocks halfs can be allocated too, 3 bits
|
||||||
|
* are required: 1 for the page, 1 for the frist half
|
||||||
|
* and 1 for the second half. Allowing the allocation
|
||||||
|
* of page quarters requires 4 more bits, for a total
|
||||||
|
* of 7. In general, if we allow splitting a page N
|
||||||
|
* times (N=0 means only the entire page can be allocated),
|
||||||
|
* then 2^(N+1)-1 bits are necessary.
|
||||||
|
*/
|
||||||
|
#define BUDDY_ALLOC_BITS_PER_PAGE ((1U << (BUDDY_ALLOC_NUM_LISTS)) - 1)
|
||||||
|
#define BUDDY_ALLOC_WORDS_PER_PAGE ((BUDDY_ALLOC_BITS_PER_PAGE + 31) / 32)
|
||||||
|
struct page_info {
|
||||||
|
uint32_t bits[BUDDY_ALLOC_WORDS_PER_PAGE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buddy_page {
|
||||||
|
struct buddy_page *prev;
|
||||||
|
struct buddy_page *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buddy {
|
||||||
|
void *base;
|
||||||
|
size_t size;
|
||||||
|
struct buddy_page *lists[BUDDY_ALLOC_NUM_LISTS];
|
||||||
|
struct page_info *info;
|
||||||
|
int num_info;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Just for convenience
|
* Just for convenience
|
||||||
*/
|
*/
|
||||||
@@ -279,6 +315,11 @@
|
|||||||
#define MIN_BLOCK_SIZE BUDDY_ALLOC_MIN_BLOCK_SIZE
|
#define MIN_BLOCK_SIZE BUDDY_ALLOC_MIN_BLOCK_SIZE
|
||||||
#define MAX_BLOCK_ALIGN_MASK (MAX_BLOCK_SIZE - 1)
|
#define MAX_BLOCK_ALIGN_MASK (MAX_BLOCK_SIZE - 1)
|
||||||
|
|
||||||
|
void *buddy_get_base(struct buddy *alloc)
|
||||||
|
{
|
||||||
|
return alloc->base;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gets the address of the i-th page of the memory pool.
|
* Gets the address of the i-th page of the memory pool.
|
||||||
* In this context, a page is a block of size MAX_BLOCK_SIZE.
|
* In this context, a page is a block of size MAX_BLOCK_SIZE.
|
||||||
@@ -289,27 +330,71 @@ page_index_to_ptr(char *base, int i)
|
|||||||
return (struct buddy_page*) (base + (i << MAX_BLOCK_LOG2));
|
return (struct buddy_page*) (base + (i << MAX_BLOCK_LOG2));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct buddy_alloc startup_empty()
|
|
||||||
{
|
|
||||||
struct buddy_alloc alloc;
|
|
||||||
alloc.base = NULL;
|
|
||||||
alloc.size = 0;
|
|
||||||
alloc.info = NULL;
|
|
||||||
alloc.num_info = 0;
|
|
||||||
for (int i = 0; i < BUDDY_ALLOC_NUM_LISTS; i++)
|
|
||||||
alloc.lists[i] = NULL;
|
|
||||||
return alloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See buddy.h
|
* See buddy.h
|
||||||
*/
|
*/
|
||||||
struct buddy_alloc buddy_startup(char *base, size_t size,
|
struct buddy *buddy_startup(char *base, size_t size)
|
||||||
struct page_info *info,
|
|
||||||
int num_info)
|
|
||||||
{
|
{
|
||||||
if (base == NULL || info == NULL)
|
assert((base && size) || (!base && !size));
|
||||||
return startup_empty();
|
|
||||||
|
struct buddy *alloc;
|
||||||
|
{
|
||||||
|
size_t pad = -(uintptr_t) base & (_Alignof(struct buddy)-1);
|
||||||
|
if (size < pad)
|
||||||
|
return NULL;
|
||||||
|
base += pad;
|
||||||
|
size -= pad;
|
||||||
|
|
||||||
|
if (size < sizeof(struct buddy))
|
||||||
|
return NULL;
|
||||||
|
alloc = (struct buddy*) base;
|
||||||
|
base += sizeof(struct buddy);
|
||||||
|
size -= sizeof(struct buddy);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t pad = -(uintptr_t) base & (_Alignof(struct page_info)-1);
|
||||||
|
if (size < pad)
|
||||||
|
return NULL;
|
||||||
|
base += pad;
|
||||||
|
size -= pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_trees = 0;
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
int num_trees_maybe = num_trees + 1;
|
||||||
|
|
||||||
|
char *p = base;
|
||||||
|
size_t l = size;
|
||||||
|
|
||||||
|
size_t tree_region = num_trees_maybe * sizeof(struct page_info);
|
||||||
|
if (tree_region > l)
|
||||||
|
break;
|
||||||
|
|
||||||
|
p += tree_region;
|
||||||
|
l -= tree_region;
|
||||||
|
|
||||||
|
size_t pad = -(uintptr_t) p & MAX_BLOCK_ALIGN_MASK;
|
||||||
|
if (pad > l)
|
||||||
|
break;
|
||||||
|
p += pad;
|
||||||
|
l -= pad;
|
||||||
|
|
||||||
|
int num_blocks = l >> MAX_BLOCK_LOG2;
|
||||||
|
|
||||||
|
if (num_blocks < num_trees_maybe)
|
||||||
|
break;
|
||||||
|
|
||||||
|
num_trees = num_trees_maybe;
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc->info = (struct page_info*) base;
|
||||||
|
alloc->num_info = num_trees;
|
||||||
|
memset(alloc->info, 0, alloc->num_info * sizeof(struct page_info));
|
||||||
|
|
||||||
|
base += num_trees * sizeof(struct page_info);
|
||||||
|
size -= num_trees * sizeof(struct page_info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the padding necessary to align the base pointer
|
* Calculate the padding necessary to align the base pointer
|
||||||
@@ -320,32 +405,23 @@ struct buddy_alloc buddy_startup(char *base, size_t size,
|
|||||||
size_t pad = -(uintptr_t) base & MAX_BLOCK_ALIGN_MASK;
|
size_t pad = -(uintptr_t) base & MAX_BLOCK_ALIGN_MASK;
|
||||||
|
|
||||||
if (pad > size)
|
if (pad > size)
|
||||||
return startup_empty();
|
return NULL;
|
||||||
|
|
||||||
base += pad;
|
base += pad;
|
||||||
size -= pad;
|
size -= pad;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Discard any bites from the end of the pool that don't
|
* Discard any bites from the end of the pool that don't
|
||||||
* make up an entire block.
|
* make up an entire block or that don't have a bit tree
|
||||||
*/
|
*/
|
||||||
size_t rem = size & MAX_BLOCK_ALIGN_MASK;
|
size = num_trees << MAX_BLOCK_LOG2;
|
||||||
size -= rem;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Discard blocks for which there isn't a page_info structure.
|
|
||||||
*/
|
|
||||||
size_t max_bytes = (size_t) num_info << MAX_BLOCK_LOG2;
|
|
||||||
if (size > max_bytes)
|
|
||||||
size = max_bytes;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make the linked list of pages
|
* Make the linked list of pages
|
||||||
*/
|
*/
|
||||||
struct buddy_page *head = NULL;
|
struct buddy_page *head = NULL;
|
||||||
struct buddy_page *tail = NULL;
|
struct buddy_page *tail = NULL;
|
||||||
int num_pages = size >> MAX_BLOCK_LOG2;
|
for (int i = 0; i < num_trees; i++) {
|
||||||
for (int i = 0; i < num_pages; i++) {
|
|
||||||
|
|
||||||
struct buddy_page *p = page_index_to_ptr(base, i);
|
struct buddy_page *p = page_index_to_ptr(base, i);
|
||||||
|
|
||||||
@@ -360,35 +436,17 @@ struct buddy_alloc buddy_startup(char *base, size_t size,
|
|||||||
p->next = NULL;
|
p->next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
alloc->base = base,
|
||||||
* Initialize the page info. The page_info bits are 0 when
|
alloc->size = size;
|
||||||
* blocks are unused, so they start at zero.
|
|
||||||
*/
|
|
||||||
assert(info);
|
|
||||||
memset(info, 0, num_info * sizeof(struct page_info));
|
|
||||||
|
|
||||||
struct buddy_alloc alloc;
|
|
||||||
alloc.base = base,
|
|
||||||
alloc.size = size;
|
|
||||||
alloc.info = info;
|
|
||||||
alloc.num_info = num_info;
|
|
||||||
|
|
||||||
// All lists are empty except for the one of larger chunks
|
// All lists are empty except for the one of larger chunks
|
||||||
for (int i = 0; i < BUDDY_ALLOC_NUM_LISTS-1; i++)
|
for (int i = 0; i < BUDDY_ALLOC_NUM_LISTS-1; i++)
|
||||||
alloc.lists[i] = NULL;
|
alloc->lists[i] = NULL;
|
||||||
alloc.lists[BUDDY_ALLOC_NUM_LISTS-1] = head;
|
alloc->lists[BUDDY_ALLOC_NUM_LISTS-1] = head;
|
||||||
|
|
||||||
return alloc;
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* See buddy.h
|
|
||||||
*/
|
|
||||||
void buddy_cleanup(struct buddy_alloc *alloc)
|
|
||||||
{
|
|
||||||
(void) alloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns true iff n is a power of 2. To understand how this works,
|
* Returns true iff n is a power of 2. To understand how this works,
|
||||||
* refer to the comment at start of the file.
|
* refer to the comment at start of the file.
|
||||||
@@ -505,7 +563,7 @@ static int first_set(size_t x)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t page_index(struct buddy_alloc *alloc, void *ptr)
|
static size_t page_index(struct buddy *alloc, void *ptr)
|
||||||
{
|
{
|
||||||
uintptr_t x = (uintptr_t) ptr;
|
uintptr_t x = (uintptr_t) ptr;
|
||||||
uintptr_t y = (uintptr_t) alloc->base;
|
uintptr_t y = (uintptr_t) alloc->base;
|
||||||
@@ -526,8 +584,7 @@ static size_t block_info_index(void *ptr, size_t len)
|
|||||||
*
|
*
|
||||||
* See the set_allocated function
|
* See the set_allocated function
|
||||||
*/
|
*/
|
||||||
static bool is_allocated(struct buddy_alloc *alloc,
|
static bool is_allocated(struct buddy *alloc, void *ptr, size_t len)
|
||||||
void *ptr, size_t len)
|
|
||||||
{
|
{
|
||||||
assert(is_pow2(len));
|
assert(is_pow2(len));
|
||||||
|
|
||||||
@@ -555,7 +612,7 @@ static bool is_allocated(struct buddy_alloc *alloc,
|
|||||||
* refer to the explanation THE BIT TREE at the start of
|
* refer to the explanation THE BIT TREE at the start of
|
||||||
* the file.
|
* the file.
|
||||||
*/
|
*/
|
||||||
static void set_allocated(struct buddy_alloc *alloc,
|
static void set_allocated(struct buddy *alloc,
|
||||||
void *ptr, size_t len, bool value)
|
void *ptr, size_t len, bool value)
|
||||||
{
|
{
|
||||||
assert(is_pow2(len));
|
assert(is_pow2(len));
|
||||||
@@ -584,7 +641,7 @@ static void set_allocated(struct buddy_alloc *alloc,
|
|||||||
* or any of its splits are marked as allocated.
|
* or any of its splits are marked as allocated.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
is_allocated_considering_splits(struct buddy_alloc *alloc,
|
is_allocated_considering_splits(struct buddy *alloc,
|
||||||
void *ptr, size_t len)
|
void *ptr, size_t len)
|
||||||
{
|
{
|
||||||
if (len == MIN_BLOCK_SIZE)
|
if (len == MIN_BLOCK_SIZE)
|
||||||
@@ -639,16 +696,14 @@ static char *parent_of(char *ptr, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
sibling_allocated_considering_splits(struct buddy_alloc *alloc,
|
sibling_allocated_considering_splits(struct buddy *alloc, void *ptr, size_t len)
|
||||||
void *ptr, size_t len)
|
|
||||||
{
|
{
|
||||||
char *sib = sibling_of(ptr, len);
|
char *sib = sibling_of(ptr, len);
|
||||||
return is_allocated_considering_splits(alloc, sib, len);
|
return is_allocated_considering_splits(alloc, sib, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
remove_sibling_from_list(struct buddy_alloc *alloc,
|
remove_sibling_from_list(struct buddy *alloc, int i, void *ptr)
|
||||||
int i, void *ptr)
|
|
||||||
{
|
{
|
||||||
size_t len = 1U << (i + MIN_BLOCK_LOG2);
|
size_t len = 1U << (i + MIN_BLOCK_LOG2);
|
||||||
struct buddy_page *sibling = (struct buddy_page*) sibling_of(ptr, len);
|
struct buddy_page *sibling = (struct buddy_page*) sibling_of(ptr, len);
|
||||||
@@ -669,8 +724,7 @@ remove_sibling_from_list(struct buddy_alloc *alloc,
|
|||||||
* len = 1 << (i + MIN_BLOCK_LOG2)
|
* len = 1 << (i + MIN_BLOCK_LOG2)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void append(struct buddy_alloc *alloc,
|
static void append(struct buddy *alloc, int i, void *ptr)
|
||||||
int i, void *ptr)
|
|
||||||
{
|
{
|
||||||
assert(i >= 0 && i < BUDDY_ALLOC_NUM_LISTS);
|
assert(i >= 0 && i < BUDDY_ALLOC_NUM_LISTS);
|
||||||
|
|
||||||
@@ -685,7 +739,7 @@ static void append(struct buddy_alloc *alloc,
|
|||||||
alloc->lists[i] = page;
|
alloc->lists[i] = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *pop(struct buddy_alloc *alloc, int i)
|
static char *pop(struct buddy *alloc, int i)
|
||||||
{
|
{
|
||||||
assert(i >= 0 && i < BUDDY_ALLOC_NUM_LISTS);
|
assert(i >= 0 && i < BUDDY_ALLOC_NUM_LISTS);
|
||||||
|
|
||||||
@@ -699,12 +753,14 @@ static char *pop(struct buddy_alloc *alloc, int i)
|
|||||||
return (char*) page;
|
return (char*) page;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *buddy_malloc(struct buddy_alloc *alloc, size_t len)
|
void *buddy_malloc(struct buddy *alloc, size_t len)
|
||||||
{
|
{
|
||||||
|
if (alloc == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (len == 0 || len > MAX_BLOCK_SIZE)
|
if (len == 0 || len > MAX_BLOCK_SIZE)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (alloc->base == NULL)
|
|
||||||
return NULL;
|
|
||||||
len = normalize_len(len);
|
len = normalize_len(len);
|
||||||
assert(len >= MIN_BLOCK_SIZE);
|
assert(len >= MIN_BLOCK_SIZE);
|
||||||
|
|
||||||
@@ -742,9 +798,11 @@ void *buddy_malloc(struct buddy_alloc *alloc, size_t len)
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void buddy_free(struct buddy_alloc *alloc,
|
void buddy_free(struct buddy *alloc, size_t len, void *ptr)
|
||||||
size_t len, void *ptr)
|
|
||||||
{
|
{
|
||||||
|
if (alloc == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if (ptr == NULL || len == 0)
|
if (ptr == NULL || len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -774,13 +832,17 @@ void buddy_free(struct buddy_alloc *alloc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool buddy_owned(struct buddy_alloc *alloc, void *ptr)
|
bool buddy_owned(struct buddy *alloc, void *ptr)
|
||||||
{
|
{
|
||||||
|
if (alloc == NULL)
|
||||||
|
return false;
|
||||||
return (uintptr_t) alloc->base <= (uintptr_t) ptr
|
return (uintptr_t) alloc->base <= (uintptr_t) ptr
|
||||||
&& (uintptr_t) alloc->base + alloc->size > (uintptr_t) ptr;
|
&& (uintptr_t) alloc->base + alloc->size > (uintptr_t) ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool buddy_allocated(struct buddy_alloc *alloc, void *ptr, size_t len)
|
bool buddy_allocated(struct buddy *alloc, void *ptr, size_t len)
|
||||||
{
|
{
|
||||||
|
if (alloc == NULL)
|
||||||
|
return false;
|
||||||
return buddy_owned(alloc, ptr) && is_allocated(alloc, ptr, len);
|
return buddy_owned(alloc, ptr) && is_allocated(alloc, ptr, len);
|
||||||
}
|
}
|
||||||
@@ -41,94 +41,50 @@
|
|||||||
* except for the fact that the pool provided by the user should at
|
* except for the fact that the pool provided by the user should at
|
||||||
* least be that big.
|
* least be that big.
|
||||||
*/
|
*/
|
||||||
#define BUDDY_ALLOC_MAX_BLOCK_LOG2 13
|
#define BUDDY_ALLOC_MAX_BLOCK_LOG2 12
|
||||||
#define BUDDY_ALLOC_MIN_BLOCK_LOG2 4
|
#define BUDDY_ALLOC_MIN_BLOCK_LOG2 4
|
||||||
|
|
||||||
_Static_assert(BUDDY_ALLOC_MIN_BLOCK_LOG2 <= BUDDY_ALLOC_MAX_BLOCK_LOG2);
|
_Static_assert(BUDDY_ALLOC_MIN_BLOCK_LOG2 <= BUDDY_ALLOC_MAX_BLOCK_LOG2);
|
||||||
_Static_assert(BUDDY_ALLOC_MIN_BLOCK_LOG2 > 3);
|
_Static_assert(BUDDY_ALLOC_MIN_BLOCK_LOG2 > 3);
|
||||||
|
|
||||||
#define BUDDY_ALLOC_NUM_LISTS (BUDDY_ALLOC_MAX_BLOCK_LOG2 - BUDDY_ALLOC_MIN_BLOCK_LOG2 + 1)
|
/*
|
||||||
#define BUDDY_ALLOC_MAX_BLOCK_SIZE (1U << BUDDY_ALLOC_MAX_BLOCK_LOG2)
|
* Handle to the allocator
|
||||||
#define BUDDY_ALLOC_MIN_BLOCK_SIZE (1U << BUDDY_ALLOC_MIN_BLOCK_LOG2)
|
*/
|
||||||
|
struct buddy;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To keep track of the allocation state of a page,
|
* Initialize the allocator. If not enough memory was provided,
|
||||||
* we need one bit for each possible block that can
|
* NULL is returned. NULL is considered to be a valid allocator
|
||||||
* be made out of it. For instance, if the page can
|
* handle, representing the empty allocator.
|
||||||
* only be allocated in its entirety, 1 bit is required.
|
|
||||||
* If the blocks halfs can be allocated too, 3 bits
|
|
||||||
* are required: 1 for the page, 1 for the frist half
|
|
||||||
* and 1 for the second half. Allowing the allocation
|
|
||||||
* of page quarters requires 4 more bits, for a total
|
|
||||||
* of 7. In general, if we allow splitting a page N
|
|
||||||
* times (N=0 means only the entire page can be allocated),
|
|
||||||
* then 2^(N+1)-1 bits are necessary.
|
|
||||||
*/
|
*/
|
||||||
#define BUDDY_ALLOC_BITS_PER_PAGE ((1U << (BUDDY_ALLOC_NUM_LISTS)) - 1)
|
struct buddy *buddy_startup(char *base, size_t size);
|
||||||
#define BUDDY_ALLOC_WORDS_PER_PAGE ((BUDDY_ALLOC_BITS_PER_PAGE + 31) / 32)
|
|
||||||
struct page_info {
|
|
||||||
uint32_t bits[BUDDY_ALLOC_WORDS_PER_PAGE];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct buddy_page {
|
|
||||||
struct buddy_page *prev;
|
|
||||||
struct buddy_page *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct buddy_alloc {
|
|
||||||
void *base;
|
|
||||||
size_t size;
|
|
||||||
struct buddy_page *lists[BUDDY_ALLOC_NUM_LISTS];
|
|
||||||
struct page_info *info;
|
|
||||||
int num_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize the allocator.
|
|
||||||
*
|
|
||||||
* The allocator will use as allocation memory the [size]
|
|
||||||
* bytes as position [base]. If the memory pool isn't
|
|
||||||
* aligned to BUDDY_ALLOC_MAX_BLOCK_SIZE, the first bytes
|
|
||||||
* are discarded.
|
|
||||||
*
|
|
||||||
* The user needs to provide the allocator with an array
|
|
||||||
* of [struct page_info] with a capacity equal to the number
|
|
||||||
* of (aligned) BUDDY_ALLOC_MAX_BLOCK_SIZE blocks in the
|
|
||||||
* pool. If less page_info structs are provided than necessary
|
|
||||||
* for the pool, the exceeding portion of the pool is
|
|
||||||
* discarded.
|
|
||||||
*/
|
|
||||||
struct buddy_alloc buddy_startup(char *base, size_t size, struct page_info *page_info, int num_page_info);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Deinitialize the allocator.
|
|
||||||
*/
|
|
||||||
void buddy_cleanup(struct buddy_alloc *alloc);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a memory region of size [len]. If allocation
|
* Allocate a memory region of size [len]. If allocation
|
||||||
* fails, NULL is returned.
|
* fails, NULL is returned.
|
||||||
*/
|
*/
|
||||||
void *buddy_malloc(struct buddy_alloc *alloc, size_t len);
|
void *buddy_malloc(struct buddy *alloc, size_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deallocate a memory region allocated using [buddy_malloc].
|
* Deallocate a memory region allocated using [buddy_malloc].
|
||||||
* The [len] argument must be the same value passed when
|
* The [len] argument must be the same value passed when
|
||||||
* allocating.
|
* allocating.
|
||||||
*/
|
*/
|
||||||
void buddy_free(struct buddy_alloc *alloc, size_t len, void *ptr);
|
void buddy_free(struct buddy *alloc, size_t len, void *ptr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns true if and only if ptr points inside of the memory
|
* Returns true if and only if ptr points inside of the memory
|
||||||
* generally available for allocation (even if currently marked
|
* generally available for allocation (even if currently marked
|
||||||
* as allocated).
|
* as allocated).
|
||||||
*/
|
*/
|
||||||
bool buddy_owned(struct buddy_alloc *alloc, void *ptr);
|
bool buddy_owned(struct buddy *alloc, void *ptr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns true if and only if the block at address ptr of size
|
* Returns true if and only if the block at address ptr of size
|
||||||
* len is owned by the allocator and marked as allocated.
|
* len is owned by the allocator and marked as allocated.
|
||||||
*/
|
*/
|
||||||
bool buddy_allocated(struct buddy_alloc *alloc, void *ptr, size_t len);
|
bool buddy_allocated(struct buddy *alloc, void *ptr, size_t len);
|
||||||
|
|
||||||
|
void *buddy_get_base(struct buddy *alloc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -4,30 +4,24 @@
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
#define NUM_PAGES 16
|
|
||||||
|
|
||||||
// This is the memory we will allocate from
|
// This is the memory we will allocate from
|
||||||
char memory[NUM_PAGES * BUDDY_ALLOC_MAX_BLOCK_SIZE];
|
char memory[1 << 20];
|
||||||
|
|
||||||
struct page_info info[NUM_PAGES]; // This is required to keep track of allocation state
|
struct buddy *alloc = buddy_startup(memory, sizeof(memory));
|
||||||
struct buddy_alloc alloc = buddy_startup(memory, sizeof(memory), info, NUM_PAGES);
|
|
||||||
|
|
||||||
// Allocate some memory (NULL is returned on failure)
|
// Allocate some memory (NULL is returned on failure)
|
||||||
// If the memory pool passed to the allocator was properly aligned,
|
char *str1 = buddy_malloc(alloc, 32);
|
||||||
// you can count to allocate any and all bytes of that pool.
|
char *str2 = buddy_malloc(alloc, 32);
|
||||||
char *str1 = buddy_malloc(&alloc, 32);
|
|
||||||
char *str2 = buddy_malloc(&alloc, 32);
|
|
||||||
|
|
||||||
strncpy(str1, "Hello", 32);
|
strncpy(str1, "Hello", 32);
|
||||||
strncpy(str2, "world", 32);
|
strncpy(str2, "world", 32);
|
||||||
|
|
||||||
printf("%s, %s!\n", str1, str2);
|
printf("%s, %s!\n", str1, str2);
|
||||||
|
|
||||||
buddy_free(&alloc, 32, str1);
|
buddy_free(alloc, 32, str1);
|
||||||
buddy_free(&alloc, 32, str2);
|
buddy_free(alloc, 32, str2);
|
||||||
|
|
||||||
buddy_free(&alloc, 32, str2); // Double frees are caught!
|
buddy_free(alloc, 32, str2); // Double frees are caught!
|
||||||
|
|
||||||
buddy_cleanup(&alloc);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -31,8 +31,7 @@ int main(void)
|
|||||||
{
|
{
|
||||||
_Alignas(PAGE_SIZE) char mem[NUM_PAGES * PAGE_SIZE];
|
_Alignas(PAGE_SIZE) char mem[NUM_PAGES * PAGE_SIZE];
|
||||||
|
|
||||||
struct page_info info[NUM_PAGES];
|
struct buddy *alloc = buddy_startup(mem, sizeof(mem));
|
||||||
struct buddy_alloc alloc = buddy_startup(mem, sizeof(mem), info, NUM_PAGES);
|
|
||||||
|
|
||||||
struct alloc_info current_allocs[MAX_ALLOCS];
|
struct alloc_info current_allocs[MAX_ALLOCS];
|
||||||
int num_current_allocs = 0;
|
int num_current_allocs = 0;
|
||||||
@@ -46,22 +45,22 @@ int main(void)
|
|||||||
int i = rand() % num_current_allocs;
|
int i = rand() % num_current_allocs;
|
||||||
struct alloc_info deallocating = current_allocs[i];
|
struct alloc_info deallocating = current_allocs[i];
|
||||||
current_allocs[i] = current_allocs[--num_current_allocs];
|
current_allocs[i] = current_allocs[--num_current_allocs];
|
||||||
fprintf(stderr, "buddy_free(%d, %d)\n", (int) deallocating.len, (int) ((uintptr_t) deallocating.ptr - (uintptr_t) alloc.base));
|
fprintf(stderr, "buddy_free(%d, %d)\n", (int) deallocating.len, (int) ((uintptr_t) deallocating.ptr - (uintptr_t) buddy_get_base(alloc)));
|
||||||
buddy_free(&alloc, deallocating.len, (void*) deallocating.ptr);
|
buddy_free(alloc, deallocating.len, (void*) deallocating.ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t len = 1 + (rand() % PAGE_SIZE);
|
size_t len = 1 + (rand() % PAGE_SIZE);
|
||||||
assert(len > 0 && len <= PAGE_SIZE);
|
assert(len > 0 && len <= PAGE_SIZE);
|
||||||
|
|
||||||
void *ptr = buddy_malloc(&alloc, len);
|
void *ptr = buddy_malloc(alloc, len);
|
||||||
|
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
failed++;
|
failed++;
|
||||||
//fprintf(stderr, "buddy_malloc(%lu) = NULL\n", len);
|
//fprintf(stderr, "buddy_malloc(%lu) = NULL\n", len);
|
||||||
} else {
|
} else {
|
||||||
//buddy_dump(&alloc, stderr);
|
//buddy_dump(&alloc, stderr);
|
||||||
fprintf(stderr, "buddy_malloc(%d) = %d\n", (int) len, (int) ((uintptr_t) ptr - (uintptr_t) alloc.base));
|
fprintf(stderr, "buddy_malloc(%d) = %d\n", (int) len, (int) ((uintptr_t) ptr - (uintptr_t) buddy_get_base(alloc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL) {
|
||||||
@@ -77,6 +76,5 @@ int main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buddy_cleanup(&alloc);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,63 +1,21 @@
|
|||||||
#include <stdio.h>
|
#include <stdlib.h>
|
||||||
#include "buddy.h"
|
#include "buddy.h"
|
||||||
|
|
||||||
#define NUM_PAGES 16
|
|
||||||
|
|
||||||
#define MIN_ALLOC_SIZE (1U << BUDDY_ALLOC_MIN_BLOCK_LOG2)
|
|
||||||
#define PAGE_SIZE (1U << BUDDY_ALLOC_MAX_BLOCK_LOG2)
|
|
||||||
#define POOL_SIZE (NUM_PAGES * PAGE_SIZE)
|
|
||||||
#define MAX_ALLOCS (POOL_SIZE / MIN_ALLOC_SIZE)
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
_Alignas(PAGE_SIZE) char mem[POOL_SIZE];
|
char mem[1<<20];
|
||||||
struct page_info info[NUM_PAGES];
|
for (int i = 0; i < 100; i++) {
|
||||||
struct buddy_alloc alloc = buddy_startup(mem, POOL_SIZE, info, NUM_PAGES);
|
|
||||||
|
|
||||||
void *allocs[MAX_ALLOCS];
|
void *base = mem;
|
||||||
|
size_t size = sizeof(mem);
|
||||||
|
|
||||||
size_t performed = 0;
|
size_t pad = rand() % size;
|
||||||
for (size_t i = 0; i < MAX_ALLOCS; i++) {
|
base += pad;
|
||||||
void *ptr = buddy_malloc(&alloc, MIN_ALLOC_SIZE);
|
size -= pad;
|
||||||
if (ptr == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
performed++;
|
size_t len = rand() % (size+1);
|
||||||
|
|
||||||
allocs[i] = ptr;
|
struct buddy *b = buddy_startup(base, len);
|
||||||
|
|
||||||
*(size_t*) ptr = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (performed == MAX_ALLOCS) {
|
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_ALLOCS; i++) {
|
|
||||||
if (*(size_t*) allocs[i] != i)
|
|
||||||
fprintf(stderr, "%p allocated twice!\n", allocs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_ALLOCS; i++) {
|
|
||||||
buddy_free(&alloc, MIN_ALLOC_SIZE, allocs[MAX_ALLOCS-i-1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
performed = 0;
|
|
||||||
for (size_t i = 0; i < MAX_ALLOCS; i++) {
|
|
||||||
void *ptr = buddy_malloc(&alloc, MIN_ALLOC_SIZE);
|
|
||||||
performed++;
|
|
||||||
|
|
||||||
allocs[i] = ptr;
|
|
||||||
|
|
||||||
*(size_t*) ptr = i + MAX_ALLOCS;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_ALLOCS; i++) {
|
|
||||||
if (*(size_t*) allocs[i] != MAX_ALLOCS + i)
|
|
||||||
fprintf(stderr, "%p reallocation error!\n", allocs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "performed=%d, expected=%d\n", (int) performed, (int) MAX_ALLOCS);
|
|
||||||
|
|
||||||
buddy_cleanup(&alloc);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user