[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