[lib][heap] have the heap pull pages out of the vm, if present

This commit is contained in:
Travis Geiselbrecht
2014-07-11 18:06:59 -07:00
parent 986d1590cb
commit 25a78c5225
3 changed files with 100 additions and 30 deletions

View File

@@ -31,9 +31,6 @@
extern void *vectab;
extern int _end_of_ram;
void *_heap_end = &_end_of_ram;
#if ARM_CM_DYNAMIC_PRIORITY_SIZE
unsigned int arm_cm_num_irq_pri_bits;
unsigned int arm_cm_irq_pri_mask;

View File

@@ -26,9 +26,6 @@
#include <arch/arm64.h>
#include <platform.h>
extern int _end_of_ram;
void *_heap_end = &_end_of_ram;
void arch_early_init(void)
{
/* set the vector base */

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008-2009,2012 Travis Geiselbrecht
* Copyright (c) 2008-2009,2012,2014 Travis Geiselbrecht
* Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -28,6 +28,7 @@
#include <list.h>
#include <rand.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <kernel/thread.h>
#include <kernel/mutex.h>
@@ -41,25 +42,36 @@
#define PADDING_FILL 0x55
#define PADDING_SIZE 64
#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
#define HEAP_MAGIC 'HEAP'
#if WITH_STATIC_HEAP
#if WITH_KERNEL_VM
#include <kernel/vm.h>
/* we will use kalloc routines to back our heap */
#if !defined(HEAP_GROW_SIZE)
#define HEAP_GROW_SIZE (4 * 1024 * 1024) /* size the heap grows by when it runs out of memory */
#endif
STATIC_ASSERT(IS_PAGE_ALIGNED(HEAP_GROW_SIZE));
#elif WITH_STATIC_HEAP
#if !defined(HEAP_START) || !defined(HEAP_LEN)
#error WITH_STATIC_HEAP set but no HEAP_START or HEAP_LEN defined
#endif
#else
// end of the binary
/* not a static vm, not using the kernel vm */
extern int _end;
extern int _end_of_ram;
// end of memory
extern void *_heap_end;
/* default to using up the rest of memory after the kernel ends */
/* may be modified by other parts of the system */
uintptr_t _heap_start = (uintptr_t)&_end;
uintptr_t _heap_end = (uintptr_t)&_end_of_ram;
#define HEAP_START ((uintptr_t)&_end)
#define HEAP_LEN ((uintptr_t)_heap_end - (uintptr_t)&_end)
#define HEAP_START ((uintptr_t)_heap_start)
#define HEAP_LEN ((uintptr_t)_heap_end - HEAP_START)
#endif
struct free_heap_chunk {
@@ -93,6 +105,8 @@ struct alloc_struct_begin {
#endif
};
static ssize_t heap_grow(size_t len);
static void dump_free_chunk(struct free_heap_chunk *chunk)
{
dprintf(INFO, "\t\tbase %p, end 0x%lx, len 0x%zx\n", chunk, (vaddr_t)chunk + chunk->len, chunk->len);
@@ -178,7 +192,7 @@ static struct free_heap_chunk *heap_insert_free_chunk(struct free_heap_chunk *ch
vaddr_t chunk_end = (vaddr_t)chunk + chunk->len;
#endif
// dprintf("%s: chunk ptr %p, size 0x%lx, chunk_end 0x%x\n", __FUNCTION__, chunk, chunk->len, chunk_end);
LTRACEF("chunk ptr %p, size 0x%zx\n", chunk, chunk->len);
struct free_heap_chunk *next_chunk;
struct free_heap_chunk *last_chunk;
@@ -311,6 +325,10 @@ void *heap_alloc(size_t size, unsigned int alignment)
size += alignment;
}
#if WITH_KERNEL_VM
int retry_count = 0;
retry:
#endif
mutex_acquire(&theheap.lock);
// walk through the list
@@ -382,6 +400,19 @@ void *heap_alloc(size_t size, unsigned int alignment)
mutex_release(&theheap.lock);
#if WITH_KERNEL_VM
/* try to grow the heap if we can */
if (ptr == NULL && retry_count == 0) {
size_t growby = MAX(HEAP_GROW_SIZE, ROUNDUP(size, PAGE_SIZE));
ssize_t err = heap_grow(growby);
if (err >= 0) {
retry_count++;
goto retry;
}
}
#endif
LTRACEF("returning ptr %p\n", ptr);
return ptr;
@@ -468,20 +499,40 @@ void heap_get_stats(struct heap_stats *ptr)
ptr->heap_low_watermark = theheap.low_watermark;
mutex_release(&theheap.lock);
}
static ssize_t heap_grow(size_t size)
{
#if WITH_KERNEL_VM
size = ROUNDUP(size, PAGE_SIZE);
void *ptr = pmm_alloc_kpages(size / PAGE_SIZE, NULL);
if (!ptr)
return ERR_NO_MEMORY;
LTRACEF("growing heap by 0x%zx bytes, new ptr %p\n", size, ptr);
heap_insert_free_chunk(heap_create_free_chunk(ptr, size, true));
/* change the heap start and end variables */
if ((uintptr_t)ptr < (uintptr_t)theheap.base)
theheap.base = ptr;
uintptr_t endptr = (uintptr_t)ptr + size;
if (endptr > (uintptr_t)theheap.base + theheap.len) {
theheap.len = (uintptr_t)endptr - (uintptr_t)theheap.base;
}
return size;
#else
return ERR_NO_MEMORY;
#endif
}
void heap_init(void)
{
LTRACE_ENTRY;
// set the heap range
theheap.base = (void *)HEAP_START;
theheap.len = HEAP_LEN;
theheap.remaining =0; // will get set by heap_insert_free_chunk()
theheap.low_watermark = theheap.len;
LTRACEF("base %p size %zd bytes\n", theheap.base, theheap.len);
// create a mutex
mutex_init(&theheap.lock);
@@ -491,14 +542,24 @@ void heap_init(void)
// initialize the delayed free list
list_initialize(&theheap.delayed_free_list);
// set the heap range
#if WITH_KERNEL_VM
theheap.base = pmm_alloc_kpages(HEAP_GROW_SIZE / PAGE_SIZE, NULL);
theheap.len = HEAP_GROW_SIZE;
if (theheap.base == 0) {
panic("HEAP: error allocating initial heap size\n");
}
#else
theheap.base = (void *)HEAP_START;
theheap.len = HEAP_LEN;
#endif
theheap.remaining = 0; // will get set by heap_insert_free_chunk()
theheap.low_watermark = theheap.len;
LTRACEF("base %p size %zd bytes\n", theheap.base, theheap.len);
// create an initial free chunk
heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len, false));
// dump heap info
// heap_dump();
// dprintf(INFO, "running heap tests\n");
// heap_test();
}
/* add a new block of memory to the heap */
@@ -521,15 +582,30 @@ STATIC_COMMAND_END(heap);
static int cmd_heap(int argc, const cmd_args *argv)
{
if (argc < 2) {
notenoughargs:
printf("not enough arguments\n");
usage:
printf("usage:\n");
printf("\t%s info\n", argv[0].str);
printf("\t%s alloc <size> [alignment]\n", argv[0].str);
printf("\t%s free <address>\n", argv[0].str);
return -1;
}
if (strcmp(argv[1].str, "info") == 0) {
heap_dump();
} else if (strcmp(argv[1].str, "alloc") == 0) {
if (argc < 3) goto notenoughargs;
void *ptr = heap_alloc(argv[2].u, (argc >= 3) ? argv[3].u : 0);
printf("heap_alloc returns %p\n", ptr);
} else if (strcmp(argv[1].str, "free") == 0) {
if (argc < 2) goto notenoughargs;
heap_free((void *)argv[2].u);
} else {
printf("unrecognized command\n");
return -1;
goto usage;
}
return 0;