[Haiku-commits] r31108 - haiku/trunk/src/apps/debugger/debugger_interface

bonefish at BerliOS bonefish at mail.berlios.de
Fri Jun 19 00:37:17 CEST 2009


Author: bonefish
Date: 2009-06-19 00:37:16 +0200 (Fri, 19 Jun 2009)
New Revision: 31108
ViewCVS: http://svn.berlios.de/viewcvs/haiku?rev=31108&view=rev

Modified:
   haiku/trunk/src/apps/debugger/debugger_interface/DebuggerInterface.cpp
   haiku/trunk/src/apps/debugger/debugger_interface/DebuggerInterface.h
Log:
We can't only use a single debug context, if we want to allow multiple threads
to play with us without blocking. Implemented a pool of debug contexts instead.


Modified: haiku/trunk/src/apps/debugger/debugger_interface/DebuggerInterface.cpp
===================================================================
--- haiku/trunk/src/apps/debugger/debugger_interface/DebuggerInterface.cpp	2009-06-18 21:45:14 UTC (rev 31107)
+++ haiku/trunk/src/apps/debugger/debugger_interface/DebuggerInterface.cpp	2009-06-18 22:37:16 UTC (rev 31108)
@@ -9,6 +9,11 @@
 
 #include <stdio.h>
 
+#include <Locker.h>
+
+#include <AutoLocker.h>
+#include <util/DoublyLinkedList.h>
+
 #include "debug_utils.h"
 
 #include "ArchitectureX86.h"
@@ -18,14 +23,211 @@
 #include "ThreadInfo.h"
 
 
+// number of debug contexts the pool does initially create
+static const int kInitialDebugContextCount = 3;
+
+// maximum number of debug contexts in the pool
+static const int kMaxDebugContextCount = 10;
+
+
+struct DebuggerInterface::DebugContext : debug_context,
+		DoublyLinkedListLinkImpl<DebugContext> {
+	DebugContext()
+	{
+		team = -1;
+		nub_port = -1;
+		reply_port = -1;
+	}
+
+	~DebugContext()
+	{
+		if (reply_port >= 0)
+			destroy_debug_context(this);
+	}
+
+	status_t Init(team_id team, port_id nubPort)
+	{
+		return init_debug_context(this, team, nubPort);
+	}
+
+	void Close()
+	{
+		if (reply_port >= 0) {
+			destroy_debug_context(this);
+			team = -1;
+			nub_port = -1;
+			reply_port = -1;
+		}
+	}
+};
+
+
+struct DebuggerInterface::DebugContextPool {
+	DebugContextPool(team_id team, port_id nubPort)
+		:
+		fLock("debug context pool"),
+		fTeam(team),
+		fNubPort(nubPort),
+		fBlockSem(-1),
+		fContextCount(0),
+		fWaiterCount(0),
+		fClosed(false)
+	{
+	}
+
+	~DebugContextPool()
+	{
+		AutoLocker<BLocker> locker(fLock);
+
+		while (DebugContext* context = fFreeContexts.RemoveHead())
+			delete context;
+
+		if (fBlockSem >= 0)
+			delete_sem(fBlockSem);
+	}
+
+	status_t Init()
+	{
+		status_t error = fLock.InitCheck();
+		if (error != B_OK)
+			return error;
+
+		fBlockSem = create_sem(0, "debug context pool block");
+		if (fBlockSem < 0)
+			return fBlockSem;
+
+		for (int i = 0; i < kInitialDebugContextCount; i++) {
+			DebugContext* context;
+			error = _CreateDebugContext(context);
+			if (error != B_OK)
+				return error;
+
+			fFreeContexts.Add(context);
+		}
+
+		return B_OK;
+	}
+
+	void Close()
+	{
+		AutoLocker<BLocker> locker(fLock);
+		fClosed = true;
+
+		for (DebugContextList::Iterator it = fFreeContexts.GetIterator();
+				DebugContext* context = it.Next();) {
+			context->Close();
+		}
+
+		for (DebugContextList::Iterator it = fUsedContexts.GetIterator();
+				DebugContext* context = it.Next();) {
+			context->Close();
+		}
+	}
+
+	DebugContext* GetContext()
+	{
+		AutoLocker<BLocker> locker(fLock);
+		DebugContext* context = fFreeContexts.RemoveHead();
+
+		if (context == NULL) {
+			if (fContextCount >= kMaxDebugContextCount
+				|| _CreateDebugContext(context) != B_OK) {
+				// wait for a free context
+				while (context == NULL) {
+					fWaiterCount++;
+					locker.Unlock();
+					while (acquire_sem(fBlockSem) != B_OK);
+					locker.Lock();
+					context = fFreeContexts.RemoveHead();
+				}
+			}
+		}
+
+		fUsedContexts.Add(context);
+
+		return context;
+	}
+
+	void PutContext(DebugContext* context)
+	{
+		AutoLocker<BLocker> locker(fLock);
+		fUsedContexts.Remove(context);
+		fFreeContexts.Add(context);
+
+		if (fWaiterCount > 0)
+			release_sem(fBlockSem);
+	}
+
+private:
+	typedef DoublyLinkedList<DebugContext> DebugContextList;
+
+private:
+	status_t _CreateDebugContext(DebugContext*& _context)
+	{
+		DebugContext* context = new(std::nothrow) DebugContext;
+		if (context == NULL)
+			return B_NO_MEMORY;
+
+		if (!fClosed) {
+			status_t error = context->Init(fTeam, fNubPort);
+			if (error != B_OK) {
+				delete context;
+				return error;
+			}
+		}
+
+		fContextCount++;
+
+		_context = context;
+		return B_OK;
+	}
+
+private:
+	BLocker				fLock;
+	team_id				fTeam;
+	port_id				fNubPort;
+	sem_id				fBlockSem;
+	int32				fContextCount;
+	int32				fWaiterCount;
+	DebugContextList	fFreeContexts;
+	DebugContextList	fUsedContexts;
+	bool				fClosed;
+};
+
+
+struct DebuggerInterface::DebugContextGetter {
+	DebugContextGetter(DebugContextPool* pool)
+		:
+		fPool(pool),
+		fContext(pool->GetContext())
+	{
+	}
+
+	~DebugContextGetter()
+	{
+		fPool->PutContext(fContext);
+	}
+
+	DebugContext* Context() const
+	{
+		return fContext;
+	}
+
+private:
+	DebugContextPool*	fPool;
+	DebugContext*		fContext;
+};
+
+// #pragma mark - DebuggerInterface
+
 DebuggerInterface::DebuggerInterface(team_id teamID)
 	:
 	fTeamID(teamID),
 	fDebuggerPort(-1),
 	fNubPort(-1),
+	fDebugContextPool(NULL),
 	fArchitecture(NULL)
 {
-	fDebugContext.reply_port = -1;
 }
 
 
@@ -33,9 +235,9 @@
 {
 	fArchitecture->RemoveReference();
 
-	destroy_debug_context(&fDebugContext);
+	Close();
 
-	Close();
+	delete fDebugContextPool;
 }
 
 
@@ -64,8 +266,12 @@
 	if (fNubPort < 0)
 		return fNubPort;
 
-	// init debug context
-	status_t error = init_debug_context(&fDebugContext, fTeamID, fNubPort);
+	// create debug context pool
+	fDebugContextPool = new(std::nothrow) DebugContextPool(fTeamID, fNubPort);
+	if (fDebugContextPool == NULL)
+		return B_NO_MEMORY;
+
+	status_t error = fDebugContextPool->Init();
 	if (error != B_OK)
 		return error;
 
@@ -203,13 +409,15 @@
 status_t
 DebuggerInterface::GetCpuState(thread_id thread, CpuState*& _state)
 {
+	DebugContextGetter contextGetter(fDebugContextPool);
+
 	debug_nub_get_cpu_state message;
-	message.reply_port = fDebugContext.reply_port;
+	message.reply_port = contextGetter.Context()->reply_port;
 	message.thread = thread;
 
 	debug_nub_get_cpu_state_reply reply;
 
-	status_t error = send_debug_message(&fDebugContext,
+	status_t error = send_debug_message(contextGetter.Context(),
 		B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), &reply,
 		sizeof(reply));
 	if (error != B_OK)

Modified: haiku/trunk/src/apps/debugger/debugger_interface/DebuggerInterface.h
===================================================================
--- haiku/trunk/src/apps/debugger/debugger_interface/DebuggerInterface.h	2009-06-18 21:45:14 UTC (rev 31107)
+++ haiku/trunk/src/apps/debugger/debugger_interface/DebuggerInterface.h	2009-06-18 22:37:16 UTC (rev 31108)
@@ -47,6 +47,11 @@
 										// returns a reference to the caller
 
 private:
+	struct DebugContext;
+	struct DebugContextPool;
+	struct DebugContextGetter;
+
+private:
 			status_t			_CreateDebugEvent(int32 messageCode,
 									const debug_debugger_message_data& message,
 									bool& _ignore, DebugEvent*& _event);
@@ -55,8 +60,7 @@
 			team_id				fTeamID;
 			port_id				fDebuggerPort;
 			port_id				fNubPort;
-			debug_context		fDebugContext;
-				// TODO: Use a debug context pool!
+			DebugContextPool*	fDebugContextPool;
 			Architecture*		fArchitecture;
 };
 




More information about the Haiku-commits mailing list