mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43:36 +01:00
kmalloc: add kmalloc_max() function
This commit is contained in:
parent
252bd4eb41
commit
7b662987f8
3 changed files with 95 additions and 0 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue