kmalloc: add kmalloc_max() function

This commit is contained in:
Lephe 2022-11-09 21:35:32 +01:00
parent 252bd4eb41
commit 7b662987f8
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
3 changed files with 95 additions and 0 deletions

View file

@ -39,6 +39,20 @@ void *krealloc(void *ptr, size_t size);
/* kfree(): Free memory allocated with kalloc() */
void kfree(void *ptr);
/* kmalloc_max(): Allocate the largest block available in an arena
This function is like kmalloc(), but it find the largest block in the arena
and returns it whole after setting its size in *size. This is useful if you
need memory to manage with another allocator, or you don't yet know the size
of the data to be generated. The block can later be shrunk with realloc().
Currently only gint-managed arenas support this operation.
@size Will be set to size of returned block (if there is one)
@arean_name Name of arena to allocate in (*cannot* be NULL)
Returns the address of the largest block available, NULL on error. */
void *kmalloc_max(size_t *size, char const *arena_name);
//---
// Extension API for new areas and statistics
//---
@ -53,6 +67,8 @@ typedef struct {
void * (*realloc)(void *ptr, size_t newsize, void *data);
/* kfree() handles ptr == NULL*/
void (*free)(void *ptr, void *data);
/* kmalloc_max() backend */
void * (*malloc_max)(size_t *size, void *data);
/* Name, should be unique; gint reserves names starting with "_" */
char const *name;

View file

@ -178,6 +178,25 @@ static block_t *best_fit(block_t *list, size_t size)
return best_match;
}
/* Find a worst fit in the list */
static block_t *worst_fit(block_t *list)
{
block_t *best_match = NULL;
size_t best_size = 0;
while(list)
{
if(list->size >= best_size)
{
best_match = list;
best_size = list->size;
}
list = next_link(list);
}
return best_match;
}
//---
// Index-level operations
//---
@ -366,6 +385,35 @@ static void *gint_realloc(void *ptr, size_t size, void *data)
return new_ptr;
}
static void *gint_malloc_max(size_t *size, void *data)
{
index_t *index = data;
stats_t *s = index->stats;
/* Find the largest available block in the largest possible class */
block_t *alloc;
for(int c = 15; c >= 0; c--)
{
block_t *list = index->classes[c];
alloc = (c < 14) ? list : worst_fit(list);
if(alloc) break;
}
if(!alloc) return NULL;
remove_link(alloc, index);
/* Mark the block as allocated and return it */
block_t *next = next_block(alloc);
alloc->used = true;
if(next) next->previous_used = true;
if(s) s->used_memory += alloc->size;
if(s) s->peak_used_memory = max(s->peak_used_memory, s->used_memory);
*size = alloc->size;
return (void *)alloc + sizeof(block_t);
}
/* kmalloc_init_arena(): Initialize an arena with gint's allocator */
void kmalloc_init_arena(kmalloc_arena_t *a, bool enable_statistics)
{
@ -375,6 +423,7 @@ void kmalloc_init_arena(kmalloc_arena_t *a, bool enable_statistics)
a->malloc = gint_malloc;
a->free = gint_free;
a->realloc = gint_realloc;
a->malloc_max = gint_malloc_max;
/* The index is located at the very start of the arena */
index_t *index = a->start;

View file

@ -131,6 +131,36 @@ void kfree(void *ptr)
a->stats.live_blocks--;
}
/* kmalloc_max(): Allocate the largest block available in an arena */
void *kmalloc_max(size_t *size, char const *name)
{
for(int i = 0; i < KMALLOC_ARENA_MAX; i++) if(arenas[i])
{
kmalloc_arena_t *a = arenas[i];
if(strcmp(a->name, name)) continue;
void *rc = a->malloc_max ? a->malloc_max(size, a->data) : NULL;
/* Maintain statistics */
struct kmalloc_stats *s = &a->stats;
if(rc)
{
s->live_blocks++;
s->peak_live_blocks = max(s->live_blocks,
s->peak_live_blocks);
s->total_volume += *size;
s->total_blocks++;
return rc;
}
else
{
s->total_failures++;
}
}
return NULL;
}
/* kmalloc_add_arena(): Add a new arena to the heap source */
bool kmalloc_add_arena(kmalloc_arena_t *arena)
{