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. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31108 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Locker.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
#include "debug_utils.h"
|
#include "debug_utils.h"
|
||||||
|
|
||||||
#include "ArchitectureX86.h"
|
#include "ArchitectureX86.h"
|
||||||
@@ -18,14 +23,211 @@
|
|||||||
#include "ThreadInfo.h"
|
#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)
|
DebuggerInterface::DebuggerInterface(team_id teamID)
|
||||||
:
|
:
|
||||||
fTeamID(teamID),
|
fTeamID(teamID),
|
||||||
fDebuggerPort(-1),
|
fDebuggerPort(-1),
|
||||||
fNubPort(-1),
|
fNubPort(-1),
|
||||||
|
fDebugContextPool(NULL),
|
||||||
fArchitecture(NULL)
|
fArchitecture(NULL)
|
||||||
{
|
{
|
||||||
fDebugContext.reply_port = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -33,9 +235,9 @@ DebuggerInterface::~DebuggerInterface()
|
|||||||
{
|
{
|
||||||
fArchitecture->RemoveReference();
|
fArchitecture->RemoveReference();
|
||||||
|
|
||||||
destroy_debug_context(&fDebugContext);
|
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
|
delete fDebugContextPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -64,8 +266,12 @@ DebuggerInterface::Init()
|
|||||||
if (fNubPort < 0)
|
if (fNubPort < 0)
|
||||||
return fNubPort;
|
return fNubPort;
|
||||||
|
|
||||||
// init debug context
|
// create debug context pool
|
||||||
status_t error = init_debug_context(&fDebugContext, fTeamID, fNubPort);
|
fDebugContextPool = new(std::nothrow) DebugContextPool(fTeamID, fNubPort);
|
||||||
|
if (fDebugContextPool == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t error = fDebugContextPool->Init();
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@@ -203,13 +409,15 @@ DebuggerInterface::GetThreadInfo(thread_id thread, ThreadInfo& info)
|
|||||||
status_t
|
status_t
|
||||||
DebuggerInterface::GetCpuState(thread_id thread, CpuState*& _state)
|
DebuggerInterface::GetCpuState(thread_id thread, CpuState*& _state)
|
||||||
{
|
{
|
||||||
|
DebugContextGetter contextGetter(fDebugContextPool);
|
||||||
|
|
||||||
debug_nub_get_cpu_state message;
|
debug_nub_get_cpu_state message;
|
||||||
message.reply_port = fDebugContext.reply_port;
|
message.reply_port = contextGetter.Context()->reply_port;
|
||||||
message.thread = thread;
|
message.thread = thread;
|
||||||
|
|
||||||
debug_nub_get_cpu_state_reply reply;
|
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,
|
B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), &reply,
|
||||||
sizeof(reply));
|
sizeof(reply));
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
|
|||||||
@@ -46,6 +46,11 @@ public:
|
|||||||
CpuState*& _state);
|
CpuState*& _state);
|
||||||
// returns a reference to the caller
|
// returns a reference to the caller
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct DebugContext;
|
||||||
|
struct DebugContextPool;
|
||||||
|
struct DebugContextGetter;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _CreateDebugEvent(int32 messageCode,
|
status_t _CreateDebugEvent(int32 messageCode,
|
||||||
const debug_debugger_message_data& message,
|
const debug_debugger_message_data& message,
|
||||||
@@ -55,8 +60,7 @@ private:
|
|||||||
team_id fTeamID;
|
team_id fTeamID;
|
||||||
port_id fDebuggerPort;
|
port_id fDebuggerPort;
|
||||||
port_id fNubPort;
|
port_id fNubPort;
|
||||||
debug_context fDebugContext;
|
DebugContextPool* fDebugContextPool;
|
||||||
// TODO: Use a debug context pool!
|
|
||||||
Architecture* fArchitecture;
|
Architecture* fArchitecture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user