Apply tweaks to handle larger addresses (thanks @HaydenKow)

This commit is contained in:
Luke Benstead 2021-02-18 20:55:03 +00:00
parent 8a02ee55cc
commit ddf23974bd
3 changed files with 59 additions and 13 deletions

View File

@ -3,6 +3,7 @@
#include <assert.h>
#include <string.h>
#define ALIGN(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#if defined(YALLOC_VALGRIND) && !defined(NVALGRIND)
# define USE_VALGRIND 1
@ -323,8 +324,8 @@ void * yalloc_alloc(void * pool, size_t size)
return NULL; /* no free block, no chance to allocate anything */ // TODO: Just read up which C standard supports single line comments and then fucking use them!
}
while (size % 4)
++size; /* round up to alignment TODO: do it the clever way */
/* round up to alignment */
size = ALIGN(size, 64);
size_t bruttoSize = size + sizeof(Header);
Header * prev = NULL;
@ -373,7 +374,7 @@ void * yalloc_alloc(void * pool, size_t size)
prev[1].next = cur[1].next;
else
{
uint16_t freeBit = isFree(root);
uint32_t freeBit = isFree(root);
root->prev = (cur[1].next & NIL) | freeBit;
}
@ -405,7 +406,7 @@ static void unlink_from_free_list(Header * pool, Header * blk)
if (isNil(blk[1].prev))
{ // the block is the first in the free-list
// make the pools first-free-pointer point to the next in the free list
uint16_t freeBit = isFree(pool);
uint32_t freeBit = isFree(pool);
pool->prev = (blk[1].next & NIL) | freeBit;
}
else
@ -528,7 +529,7 @@ void yalloc_free(void * pool_, void * p)
// now the freed block is the first in the free-list
// update the offset to the first element of the free list
uint16_t freeBit = isFree(pool); // remember the free-bit of the offset
uint32_t freeBit = isFree(pool); // remember the free-bit of the offset
pool->prev = HDR_OFFSET(cur) | freeBit; // update the offset and restore the free-bit
_yalloc_validate(pool);
_protect_pool(pool);
@ -576,6 +577,43 @@ size_t yalloc_count_free(void * pool_)
return bruttoFree - sizeof(Header);
}
size_t yalloc_count_continuous(void * pool_)
{
assert_is_pool(pool_);
_unprotect_pool(pool_);
assert(!_yalloc_defrag_in_progress(pool_));
Header * pool = (Header*)pool_;
size_t largestFree = 0;
Header * cur = pool;
_yalloc_validate(pool);
for (;;)
{
if (isFree(cur))
{ // it is a free block
size_t temp = (uintptr_t)HDR_PTR(cur->next) - (uintptr_t)cur;
if(temp > largestFree)
largestFree = temp;
}
if (isNil(cur->next))
break;
cur = HDR_PTR(cur->next);
}
_protect_pool(pool);
if (largestFree < sizeof(Header))
{
internal_assert(!largestFree); // free space should always be a multiple of sizeof(Header)
return 0;
}
return largestFree - sizeof(Header);
}
void * yalloc_first_used(void * pool)
{
assert_is_pool(pool);
@ -654,7 +692,7 @@ void yalloc_defrag_start(void * pool_)
internal_assert(!isFree(blk));
// mark the pool as "defragementation in progress"
uint16_t freeBit = isFree(pool);
uint32_t freeBit = isFree(pool);
pool->prev = (HDR_OFFSET(blk) & NIL) | freeBit;
_yalloc_validate(pool);

View File

@ -12,7 +12,7 @@ API of the yalloc allocator.
/**
Maximum supported pool size. yalloc_init() will fail for larger pools.
*/
#define MAX_POOL_SIZE ((2 << 16) - 4)
#define MAX_POOL_SIZE ((2 << 24) - 4)
/**
Creates a pool inside a given buffer.
@ -77,6 +77,14 @@ After defragmentation the first allocation with the returned size is guaranteed
*/
size_t yalloc_count_free(void * pool);
/**
Returns the maximum continuous free area.
@param pool The starting address of an initialized pool.
@return Number of free bytes that exist continuously.
*/
size_t yalloc_count_continuous(void * pool_);
/**
Queries the usable size of an allocated block.

View File

@ -5,19 +5,19 @@
typedef struct
{
uint16_t prev; // low bit set if free
uint16_t next; // for used blocks: low bit set if unused header at the end
uint32_t prev; // low bit set if free
uint32_t next; // for used blocks: low bit set if unused header at the end
} Header;
// NOTE: We have 32bit aligned data and 16bit offsets where the lowest bit is used as flag. So we remove the low bit and shift by 1 to address 128k bytes with the 15bit significant offset bits.
#define NIL 0xFFFEu
#define NIL 0xFFFFFFFEu
// return Header-address for a prev/next
#define HDR_PTR(offset) ((Header*)((char*)pool + (((offset) & NIL)<<1)))
// return a prev/next for a Header-address
#define HDR_OFFSET(blockPtr) ((uint16_t)(((char*)blockPtr - (char*)pool) >> 1))
#define HDR_OFFSET(blockPtr) ((uint32_t)(((char*)blockPtr - (char*)pool) >> 1))
#ifndef YALLOC_INTERNAL_VALIDATE
# ifdef NDEBUG
@ -40,9 +40,9 @@ In other cases this should be deactivated.
#endif
// detects offsets that point nowhere
static inline int isNil(uint16_t offset)
static inline int isNil(uint32_t offset)
{
return (offset | 1) == 0xFFFF;
return (offset | 1) == 0xFFFFFFFF;
}
static inline int isFree(Header * hdr)