[Haiku-commits] r30949 - in haiku/trunk: build/config_headers headers/private/kernel src/system/kernel/debug
bonefish at mail.berlios.de
bonefish at mail.berlios.de
Wed Jun 3 14:28:54 CEST 2009
Author: bonefish
Date: 2009-06-03 14:28:49 +0200 (Wed, 03 Jun 2009)
New Revision: 30949
ViewCVS: http://svn.berlios.de/viewcvs/haiku?rev=30949&view=rev
Added:
haiku/trunk/headers/private/kernel/debug_heap.h
haiku/trunk/src/system/kernel/debug/debug_heap.cpp
Modified:
haiku/trunk/build/config_headers/kernel_debug_config.h
haiku/trunk/src/system/kernel/debug/Jamfile
haiku/trunk/src/system/kernel/debug/debug.cpp
haiku/trunk/src/system/kernel/debug/debug_commands.cpp
haiku/trunk/src/system/kernel/debug/debug_parser.cpp
Log:
Replaced the temporary storage used in the kernel debug command parser. We now
have a simple dedicated heap for the kernel debugger with stacked allocation
pools (deleting a pool frees all memory allocated in it). The heap should
eventually be used for all commands that need temporary storage too large for
the stack instead of each using its own static buffer.
Modified: haiku/trunk/build/config_headers/kernel_debug_config.h
===================================================================
--- haiku/trunk/build/config_headers/kernel_debug_config.h 2009-06-03 12:16:25 UTC (rev 30948)
+++ haiku/trunk/build/config_headers/kernel_debug_config.h 2009-06-03 12:28:49 UTC (rev 30949)
@@ -18,6 +18,9 @@
// benaphore-style.
#define KDEBUG KDEBUG_LEVEL_2
+// Size of the heap used by the kernel debugger.
+#define KDEBUG_HEAP (64 * 1024)
+
// Set to 0 to disable support for kernel breakpoints.
#define KERNEL_BREAKPOINTS 1
Added: haiku/trunk/headers/private/kernel/debug_heap.h
===================================================================
--- haiku/trunk/headers/private/kernel/debug_heap.h 2009-06-03 12:16:25 UTC (rev 30948)
+++ haiku/trunk/headers/private/kernel/debug_heap.h 2009-06-03 12:28:49 UTC (rev 30949)
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2009, Ingo Weinhold, ingo_weinhold at gmx.de
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_DEBUG_HEAP_H
+#define _KERNEL_DEBUG_HEAP_H
+
+#include <debug.h>
+
+
+struct DebugAllocPool;
+typedef struct DebugAllocPool debug_alloc_pool;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+debug_alloc_pool* create_debug_alloc_pool();
+void delete_debug_alloc_pool(debug_alloc_pool* pool);
+void* debug_malloc(size_t size);
+void debug_free(void* address);
+void debug_heap_init();
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+
+struct kdebug_alloc_t {};
+extern const kdebug_alloc_t kdebug_alloc;
+
+inline void*
+operator new(size_t size, const kdebug_alloc_t&) throw()
+{
+ return debug_malloc(size);
+}
+
+namespace DebugAlloc {
+ template<typename Type>
+ inline void
+ destroy(Type* object)
+ {
+ if (object != NULL) {
+ object->~Type();
+ debug_free(object);
+ // NOTE: Doesn't work for multiple inheritence!
+ }
+ }
+}
+
+struct DebugAllocPoolScope {
+ DebugAllocPoolScope()
+ {
+ fPool = create_debug_alloc_pool();
+ }
+
+ ~DebugAllocPoolScope()
+ {
+ delete_debug_alloc_pool(fPool);
+ }
+
+private:
+ DebugAllocPool* fPool;
+};
+
+#endif // __cplusplus
+
+#endif /* _KERNEL_DEBUG_HEAP_H */
Modified: haiku/trunk/src/system/kernel/debug/Jamfile
===================================================================
--- haiku/trunk/src/system/kernel/debug/Jamfile 2009-06-03 12:16:25 UTC (rev 30948)
+++ haiku/trunk/src/system/kernel/debug/Jamfile 2009-06-03 12:28:49 UTC (rev 30949)
@@ -10,6 +10,7 @@
debug.cpp
debug_builtin_commands.cpp
debug_commands.cpp
+ debug_heap.cpp
debug_paranoia.cpp
debug_parser.cpp
debug_variables.cpp
Modified: haiku/trunk/src/system/kernel/debug/debug.cpp
===================================================================
--- haiku/trunk/src/system/kernel/debug/debug.cpp 2009-06-03 12:16:25 UTC (rev 30948)
+++ haiku/trunk/src/system/kernel/debug/debug.cpp 2009-06-03 12:28:49 UTC (rev 30949)
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, Ingo Weinhold, ingo_weinhold at gmx.de.
+ * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold at gmx.de.
* Copyright 2002-2008, Axel Dörfler, axeld at pinc-software.de.
* Distributed under the terms of the MIT License.
*
@@ -13,6 +13,7 @@
#include <cpu.h>
#include <debug.h>
+#include <debug_heap.h>
#include <debug_paranoia.h>
#include <driver_settings.h>
#include <frame_buffer_console.h>
@@ -665,6 +666,8 @@
int32 previousCPU = sDebuggerOnCPU;
sDebuggerOnCPU = smp_get_current_cpu();
+ DebugAllocPool* allocPool = create_debug_alloc_pool();
+
kprintf("Welcome to Kernel Debugging Land...\n");
if (struct thread* thread = thread_get_current_thread()) {
@@ -721,6 +724,8 @@
sCurrentLine = 0;
}
+ delete_debug_alloc_pool(allocPool);
+
sDebuggerOnCPU = previousCPU;
}
@@ -1210,6 +1215,7 @@
debug_builtin_commands_init();
+ debug_heap_init();
debug_variables_init();
frame_buffer_console_init(args);
arch_debug_console_init_settings(args);
Modified: haiku/trunk/src/system/kernel/debug/debug_commands.cpp
===================================================================
--- haiku/trunk/src/system/kernel/debug/debug_commands.cpp 2009-06-03 12:16:25 UTC (rev 30948)
+++ haiku/trunk/src/system/kernel/debug/debug_commands.cpp 2009-06-03 12:28:49 UTC (rev 30949)
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, Ingo Weinhold, ingo_weinhold at gmx.de
+ * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold at gmx.de
* Copyright 2002-2008, Axel Dörfler, axeld at pinc-software.de
* Distributed under the terms of the MIT License.
*
@@ -16,6 +16,7 @@
#include <KernelExport.h>
#include <debug.h>
+#include <debug_heap.h>
#include <lock.h>
#include <thread.h>
#include <util/AutoLock.h>
@@ -273,6 +274,9 @@
// replace argv[0] with the actual command name
argv[0] = (char *)command->name;
+ DebugAllocPoolScope allocPoolScope;
+ // Will automatically clean up all allocations the command leaves over.
+
// Invoking the command directly might be useful when debugging debugger
// commands.
if (gInvokeCommandDirectly)
Added: haiku/trunk/src/system/kernel/debug/debug_heap.cpp
===================================================================
--- haiku/trunk/src/system/kernel/debug/debug_heap.cpp 2009-06-03 12:16:25 UTC (rev 30948)
+++ haiku/trunk/src/system/kernel/debug/debug_heap.cpp 2009-06-03 12:28:49 UTC (rev 30949)
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2009, Ingo Weinhold, ingo_weinhold at gmx.de
+ * Distributed under the terms of the MIT License.
+ */
+
+#include <debug_heap.h>
+
+#include <new>
+
+#include <util/AutoLock.h>
+
+
+#define INITIAL_HEAP_SIZE B_PAGE_SIZE
+
+static char sInitialHeap[INITIAL_HEAP_SIZE];
+static void* sHeapBase = sInitialHeap;
+static size_t sHeapSize = INITIAL_HEAP_SIZE;
+
+const kdebug_alloc_t kdebug_alloc = {};
+
+
+struct allocation_header {
+ uint32 size : 31; // size in allocation_header units
+ bool free : 1;
+ uint32 previous;
+};
+
+struct free_entry : allocation_header {
+ uint32 previous_free;
+ uint32 next_free;
+};
+
+
+struct DebugAllocPool {
+ void Init(void* heap, size_t heapSize)
+ {
+ fParent = NULL;
+ fChild = NULL;
+
+ uint32 size = heapSize / 8;
+ fBase = (allocation_header*)heap - 1;
+ fEnd = size + 1;
+ fFirstFree = 0;
+ fLastFree = 0;
+
+ // add free entry spanning the whole area
+ fBase[1].size = size - 1;
+ fBase[1].previous = 0;
+ _InsertFreeEntry(1);
+ }
+
+ DebugAllocPool* CreateChildPool()
+ {
+ // do we already have a child pool?
+ if (fChild != NULL)
+ return NULL;
+
+ // create the pool object
+ DebugAllocPool* pool
+ = (DebugAllocPool*)Allocate(sizeof(DebugAllocPool));
+ if (pool == NULL)
+ return NULL;
+
+ // do we have enough free space?
+ if (fLastFree == 0 || fBase[fLastFree].size < 2) {
+ Free(pool);
+ return NULL;
+ }
+
+ allocation_header* header = &fBase[fLastFree];
+ _RemoveFreeEntry(fLastFree);
+
+ pool->Init(header + 1, header->size * 8);
+ pool->fParent = this;
+
+ return fChild = pool;
+ }
+
+ void Destroy()
+ {
+ if (fParent != NULL) {
+ fParent->fChild = NULL;
+ fParent->Free(fBase + 1);
+ }
+ }
+
+ DebugAllocPool* Parent() const
+ {
+ return fParent;
+ }
+
+ void* Allocate(size_t size)
+ {
+ size = (size + 7) / 8;
+ uint32 index = fFirstFree;
+ while (index != 0 && fBase[index].size < size)
+ index = ((free_entry*)&fBase[index])->next_free;
+
+ if (index == 0)
+ return NULL;
+
+ _RemoveFreeEntry(index);
+
+ // if the entry is big enough, we split it
+ if (fBase[index].size - size >= 2) {
+ uint32 next = index + 1 + size;
+ uint32 nextNext = index + 1 + fBase[index].size;
+ fBase[next].size = fBase[index].size - size - 1;
+ fBase[next].previous = index;
+ fBase[index].size = size;
+ _InsertFreeEntry(next);
+
+ if (nextNext < fEnd)
+ fBase[nextNext].previous = next;
+ }
+
+ return &fBase[index + 1];
+ }
+
+ void Free(void* address)
+ {
+ // check address
+ if (((addr_t)address & 7) != 0 || address <= fBase + 1
+ || address >= fBase + fEnd) {
+ kprintf("DebugAllocator::Free(%p): bad address\n", address);
+ return;
+ }
+
+ // get header
+ allocation_header* header = (allocation_header*)address - 1;
+ uint32 index = header - fBase;
+ if (header->free) {
+ kprintf("DebugAllocator::Free(%p): double free\n", address);
+ return;
+ }
+
+ uint32 next = index + 1 + header->size;
+
+ // join with previous, if possible
+ if (index > 1 && fBase[header->previous].free) {
+ uint32 previous = header->previous;
+ _RemoveFreeEntry(previous);
+
+ fBase[previous].size += 1 + header->size;
+ fBase[next].previous = previous;
+
+ index = previous;
+ header = fBase + index;
+ }
+
+ // join with next, if possible
+ if (next < fEnd && fBase[next].free) {
+ _RemoveFreeEntry(next);
+
+ header->size += 1 + fBase[next].size;
+
+ uint32 nextNext = index + 1 + header->size;
+ if (nextNext < fEnd)
+ fBase[nextNext].previous = index;
+ }
+
+ _InsertFreeEntry(index);
+ }
+
+private:
+ void _InsertFreeEntry(uint32 index)
+ {
+ // find the insertion point -- list is sorted by ascending size
+ uint32 size = fBase[index].size;
+ uint32 next = fFirstFree;
+ while (next != 0 && size > fBase[next].size)
+ next = ((free_entry*)&fBase[next])->next_free;
+
+ // insert
+ uint32 previous;
+ if (next != 0) {
+ previous = ((free_entry*)&fBase[next])->previous_free;
+ ((free_entry*)&fBase[next])->previous_free = index;
+ } else {
+ previous = fLastFree;
+ fLastFree = index;
+ }
+
+ if (previous != 0)
+ ((free_entry*)&fBase[previous])->next_free = index;
+ else
+ fFirstFree = index;
+
+ ((free_entry*)&fBase[index])->previous_free = previous;
+ ((free_entry*)&fBase[index])->next_free = next;
+
+ fBase[index].free = true;
+ }
+
+ void _RemoveFreeEntry(uint32 index)
+ {
+ uint32 previous = ((free_entry*)&fBase[index])->previous_free;
+ uint32 next = ((free_entry*)&fBase[index])->next_free;
+
+ if (previous != 0)
+ ((free_entry*)&fBase[previous])->next_free = next;
+ else
+ fFirstFree = next;
+
+ if (next != 0)
+ ((free_entry*)&fBase[next])->previous_free = previous;
+ else
+ fLastFree = previous;
+
+ fBase[index].free = false;
+ }
+
+private:
+ DebugAllocPool* fParent;
+ DebugAllocPool* fChild;
+ allocation_header* fBase; // actually base - 1, so that index 0 is
+ // invalid
+ uint32 fEnd;
+ uint32 fFirstFree;
+ uint32 fLastFree;
+};
+
+
+static DebugAllocPool* sCurrentPool;
+static DebugAllocPool sInitialPool;
+
+
+debug_alloc_pool*
+create_debug_alloc_pool()
+{
+ if (sCurrentPool == NULL) {
+ sInitialPool.Init(sHeapBase, sHeapSize);
+ sCurrentPool = &sInitialPool;
+ return sCurrentPool;
+ }
+
+ DebugAllocPool* pool = sCurrentPool->CreateChildPool();
+ if (pool == NULL)
+ return NULL;
+
+ sCurrentPool = pool;
+ return sCurrentPool;
+}
+
+
+void
+delete_debug_alloc_pool(debug_alloc_pool* pool)
+{
+ if (pool == NULL || sCurrentPool == NULL)
+ return;
+
+ // find the pool in the hierarchy
+ DebugAllocPool* otherPool = sCurrentPool;
+ while (otherPool != NULL && otherPool != pool)
+ otherPool = otherPool->Parent();
+
+ if (otherPool == NULL)
+ return;
+
+ // destroy the pool
+ sCurrentPool = pool->Parent();
+ pool->Destroy();
+
+ if (pool != &sInitialPool)
+ debug_free(pool);
+}
+
+
+void*
+debug_malloc(size_t size)
+{
+ if (sCurrentPool == NULL)
+ return NULL;
+
+ return sCurrentPool->Allocate(size);
+}
+
+
+void
+debug_free(void* address)
+{
+ if (address != NULL && sCurrentPool != NULL)
+ sCurrentPool->Free(address);
+}
+
+
+void
+debug_heap_init()
+{
+ // create the heap area
+ void* base;
+ area_id area = create_area("kdebug heap", (void**)&base,
+ B_ANY_KERNEL_ADDRESS, KDEBUG_HEAP, B_FULL_LOCK,
+ B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
+ if (area < 0)
+ return;
+
+ // switch from the small static buffer to the area
+ InterruptsLocker locker;
+ sHeapBase = base;
+ sHeapSize = KDEBUG_HEAP;
+}
Modified: haiku/trunk/src/system/kernel/debug/debug_parser.cpp
===================================================================
--- haiku/trunk/src/system/kernel/debug/debug_parser.cpp 2009-06-03 12:16:25 UTC (rev 30948)
+++ haiku/trunk/src/system/kernel/debug/debug_parser.cpp 2009-06-03 12:28:49 UTC (rev 30949)
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, Ingo Weinhold, ingo_weinhold at gmx.de
+ * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold at gmx.de
* Copyright 2006, Stephan Aßmus, superstippi at gmx.de
* Distributed under the terms of the MIT License.
*/
@@ -14,6 +14,8 @@
#include <KernelExport.h>
+#include <debug_heap.h>
+
#include "debug_commands.h"
#include "debug_variables.h"
@@ -46,7 +48,6 @@
static const int kJumpBufferCount = 10;
static const int kMaxArgumentCount = 64;
-static const size_t kTemporaryStorageSize = 10240;
static jmp_buf sJumpBuffers[kJumpBufferCount];
static int sNextJumpBufferIndex = 0;
@@ -57,10 +58,6 @@
static char sTempBuffer[128];
// for composing debug output etc.
-// temporary storage for command argument vectors and the arguments itself
-static uint8 sTemporaryStorage[kTemporaryStorageSize];
-static size_t sTemporaryStorageUsed = 0;
-
enum {
TOKEN_ASSIGN_FLAG = 0x100,
TOKEN_FLAGS = TOKEN_ASSIGN_FLAG,
@@ -143,47 +140,19 @@
}
-// #pragma mark - temporary storage
-
-
static void*
-allocate_temp_storage(size_t size)
+checked_malloc(size_t size)
{
- // 8 byte align
- size = (size + 7) & ~7;
-
- if (sTemporaryStorageUsed + size > kTemporaryStorageSize) {
- parse_exception("out of temporary storage for command execution", -1);
+ void* address = debug_malloc(size);
+ if (address == NULL) {
+ parse_exception("out of memory for command execution", -1);
return NULL;
}
- void* buffer = sTemporaryStorage + sTemporaryStorageUsed;
- sTemporaryStorageUsed += size;
-
- return buffer;
+ return address;
}
-static void
-free_temp_storage(void* _buffer)
-{
- uint8* buffer = (uint8*)_buffer;
-
- if (buffer == NULL)
- return;
-
- // must be freed in the reverse allocation order
- if (buffer < sTemporaryStorage
- || buffer > sTemporaryStorage + sTemporaryStorageUsed) {
- panic("Invalid pointer passed to free_temp_storage(): %p, temp "
- "storage base: %p", buffer, sTemporaryStorage);
- return;
- }
-
- sTemporaryStorageUsed = buffer - sTemporaryStorage;
-}
-
-
// #pragma mark - Tokenizer
@@ -750,7 +719,7 @@
uint64
ExpressionParser::_ParseCommandPipe(int& returnCode)
{
- debugger_command_pipe* pipe = (debugger_command_pipe*)allocate_temp_storage(
+ debugger_command_pipe* pipe = (debugger_command_pipe*)checked_malloc(
sizeof(debugger_command_pipe));
pipe->segment_count = 0;
@@ -773,7 +742,7 @@
// invoke the pipe
returnCode = invoke_debugger_command_pipe(pipe);
- free_temp_storage(pipe);
+ debug_free(pipe);
return get_debug_variable("_", 0);
}
@@ -806,8 +775,7 @@
}
// allocate temporary buffer for the argument vector
- char** argv = (char**)allocate_temp_storage(
- kMaxArgumentCount * sizeof(char*));
+ char** argv = (char**)checked_malloc(kMaxArgumentCount * sizeof(char*));
int argc = 0;
argv[argc++] = (char*)command->name;
@@ -955,7 +923,7 @@
if (length < 0)
length = strlen(argument);
length++;
- char* buffer = (char*)allocate_temp_storage(length);
+ char* buffer = (char*)checked_malloc(length);
strlcpy(buffer, argument, length);
argv[argc++] = buffer;
@@ -1169,9 +1137,8 @@
bool success;
uint64 result;
- void* temporaryStorageMark = allocate_temp_storage(0);
- // get a temporary storage mark, so we can cleanup everything that
- // is allocated during the evaluation
+ DebugAllocPoolScope allocPoolScope;
+ // Will clean up all allocations when we return.
if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) {
result = ExpressionParser().EvaluateExpression(expression);
@@ -1190,9 +1157,6 @@
sNextJumpBufferIndex--;
- // cleanup temp allocations
- free_temp_storage(temporaryStorageMark);
-
if (success && _result != NULL)
*_result = result;
@@ -1210,9 +1174,8 @@
}
int returnCode = 0;
- void* temporaryStorageMark = allocate_temp_storage(0);
- // get a temporary storage mark, so we can cleanup everything that
- // is allocated during the evaluation
+ DebugAllocPoolScope allocPoolScope;
+ // Will clean up all allocations when we return.
if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) {
ExpressionParser().EvaluateCommand(commandLine, returnCode);
@@ -1226,9 +1189,6 @@
sNextJumpBufferIndex--;
- // cleanup temp allocations
- free_temp_storage(temporaryStorageMark);
-
return returnCode;
}
@@ -1244,9 +1204,8 @@
}
status_t error;
- void* temporaryStorageMark = allocate_temp_storage(0);
- // get a temporary storage mark, so we can cleanup everything that
- // is allocated during the evaluation
+ DebugAllocPoolScope allocPoolScope;
+ // Will clean up all allocations when we return.
if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) {
error = ExpressionParser().ParseNextCommandArgument(expressionString,
@@ -1262,8 +1221,5 @@
sNextJumpBufferIndex--;
- // cleanup temp allocations
- free_temp_storage(temporaryStorageMark);
-
return error;
}
More information about the Haiku-commits
mailing list