Use a dedicated heap to allocate everything that is needed during heap growth.

This eliminates the edge case where the grow thread would not be able to create
a new area because no memory could be allocated for the allocation of the area.
As this case cannot happen anymore, it is also not possible to deadlock in
memalign. Therefore the timeout (which would only have prevented the deadlock
but wouldn't have solved the edge case anyway) has been removed too.
Add options to dump the dedicated grow heap and to only print the current heap
count to the "heap" debugger command.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23994 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2008-02-18 01:04:19 +00:00
parent 74672cf53c
commit cf46897b4c
2 changed files with 71 additions and 13 deletions
+4 -3
View File
@@ -11,10 +11,11 @@
#include <OS.h>
// allocate 16MB initial heap for the kernel
#define INITIAL_HEAP_SIZE 16 * 1024 * 1024
#define INITIAL_HEAP_SIZE 16 * 1024 * 1024
// grow by another 8MB each time the heap runs out of memory
#define HEAP_GROW_SIZE 8 * 1024 * 1024
#define HEAP_GROW_SIZE 8 * 1024 * 1024
// allocate a dedicated 2MB area for dynamic growing
#define HEAP_DEDICATED_GROW_SIZE 2 * 1024 * 1024
#ifdef __cplusplus
+67 -10
View File
@@ -83,6 +83,8 @@ typedef struct heap_allocator_s {
static heap_allocator *sHeapList = NULL;
static heap_allocator *sLastGrowRequest = NULL;
static heap_allocator *sGrowHeap = NULL;
static thread_id sHeapGrowThread = -1;
static sem_id sHeapGrowSem = -1;
static sem_id sHeapGrownNotify = -1;
@@ -209,6 +211,26 @@ dump_allocator(heap_allocator *heap)
static int
dump_heap_list(int argc, char **argv)
{
if (argc == 2) {
if (strcmp(argv[1], "grow") == 0) {
// only dump dedicated grow heap info
dprintf("dedicated grow heap:\n");
dump_allocator(sGrowHeap);
} else if (strcmp(argv[1], "stats") == 0) {
uint32 heapCount = 0;
heap_allocator *heap = sHeapList;
while (heap) {
heapCount++;
heap = heap->next;
}
dprintf("current heap count: %ld\n", heapCount);
} else
print_debugger_command_usage(argv[0]);
return 0;
}
heap_allocator *heap = sHeapList;
while (heap) {
dump_allocator(heap);
@@ -707,7 +729,7 @@ heap_memalign(heap_allocator *heap, size_t alignment, size_t size,
TRACE(("memalign(): asked to allocate %lu bytes, returning pointer %p\n", size, address));
if (heap->next == NULL) {
if (heap->next == NULL && shouldGrow) {
// suggest growing if we are the last heap and we have
// less than three free pages left
*shouldGrow = (heap->free_pages == NULL
@@ -998,7 +1020,11 @@ heap_init(addr_t base, size_t size)
sHeapList = heap_attach(base, size, false);
// set up some debug commands
add_debugger_command("heap", &dump_heap_list, "Dump stats about the kernel heap(s)");
add_debugger_command_etc("heap", &dump_heap_list,
"Dump infos about the kernel heap(s)", "[(\"grow\" | \"stats\")]\n"
"Dump infos about the kernel heap(s). If \"grow\" is specified, only\n"
"infos about the dedicated grow heap are printed. If \"stats\" is\n"
"given as the argument, currently only the heap count is printed\n", 0);
#if KERNEL_HEAP_LEAK_CHECK
add_debugger_command_etc("allocations", &dump_allocations,
"Dump current allocations", "[(\"team\" | \"thread\") <id>] [\"stats\"]\n"
@@ -1041,14 +1067,31 @@ heap_init_post_sem()
status_t
heap_init_post_thread()
{
thread_id thread = spawn_kernel_thread(heap_grow_thread, "heap grower",
B_URGENT_PRIORITY, NULL);
if (thread < 0) {
panic("heap_init_post_thread(): cannot create heap grow thread\n");
void *dedicated = NULL;
area_id area = create_area("heap dedicated grow", &dedicated,
B_ANY_KERNEL_BLOCK_ADDRESS, HEAP_DEDICATED_GROW_SIZE, B_FULL_LOCK,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
if (area < 0) {
panic("heap_init_post_thread(): cannot allocate dedicated grow memory\n");
return area;
}
sGrowHeap = heap_attach((addr_t)dedicated, HEAP_DEDICATED_GROW_SIZE, true);
if (sGrowHeap == NULL) {
panic("heap_init_post_thread(): failed to attach dedicated grow heap\n");
delete_area(area);
return B_ERROR;
}
send_signal_etc(thread, SIGCONT, B_DO_NOT_RESCHEDULE);
sHeapGrowThread = spawn_kernel_thread(heap_grow_thread, "heap grower",
B_URGENT_PRIORITY, NULL);
if (sHeapGrowThread < 0) {
panic("heap_init_post_thread(): cannot create heap grow thread\n");
delete_area(area);
return sHeapGrowThread;
}
send_signal_etc(sHeapGrowThread, SIGCONT, B_DO_NOT_RESCHEDULE);
return B_OK;
}
@@ -1070,6 +1113,17 @@ memalign(size_t alignment, size_t size)
return NULL;
}
if (thread_get_current_thread_id() == sHeapGrowThread) {
// this is the grower thread, allocate from our dedicated memory
void *result = heap_memalign(sGrowHeap, alignment, size, NULL);
if (result == NULL) {
panic("heap: grow thread ran out of dedicated memory!\n");
return NULL;
}
return result;
}
heap_allocator *heap = sHeapList;
while (heap) {
bool shouldGrow = false;
@@ -1078,9 +1132,8 @@ memalign(size_t alignment, size_t size)
// the last heap will or has run out of memory, notify the grower
sLastGrowRequest = heap;
if (result == NULL) {
// urgent request, do the request and wait for at max 250ms
release_sem(sHeapGrowSem);
acquire_sem_etc(sHeapGrownNotify, 1, B_RELATIVE_TIMEOUT, 250000);
// urgent request, do the request and wait
switch_sem(sHeapGrowSem, sHeapGrownNotify);
} else {
// not so urgent, just notify the grower
release_sem_etc(sHeapGrowSem, 1, B_DO_NOT_RESCHEDULE);
@@ -1131,6 +1184,10 @@ free(void *address)
heap = heap->next;
}
// maybe it was allocated from the dedicated grow heap
if (heap_free(sGrowHeap, address) == B_OK)
return;
panic("free(): free failed for address %p\n", address);
}