Refactor DebugReportGenerator to use jobs.

- Instead of asking nodes to resolve themselves directly,
  DebugReportGenerator now uses the interface listener to ask the
  debugger's workers to resolve them on its behalf.
This commit is contained in:
Rene Gollent 2012-12-11 22:50:49 -05:00
parent 00e7e607ef
commit be56273bbb
3 changed files with 67 additions and 26 deletions

View File

@ -28,6 +28,7 @@
#include "Thread.h"
#include "Type.h"
#include "UiUtils.h"
#include "UserInterface.h"
#include "Value.h"
#include "ValueLoader.h"
#include "ValueLocation.h"
@ -35,13 +36,17 @@
#include "ValueNodeManager.h"
DebugReportGenerator::DebugReportGenerator(::Team* team)
DebugReportGenerator::DebugReportGenerator(::Team* team,
UserInterfaceListener* listener)
:
BLooper("DebugReportGenerator"),
fTeam(team),
fArchitecture(team->GetArchitecture()),
fTeamDataSem(-1),
fNodeManager(NULL)
fNodeManager(NULL),
fListener(listener),
fWaitingNode(NULL),
fTraceWaitingThread(NULL)
{
fTeam->AddListener(this);
fArchitecture->AcquireReference();
@ -52,8 +57,10 @@ DebugReportGenerator::~DebugReportGenerator()
{
fTeam->RemoveListener(this);
fArchitecture->ReleaseReference();
if (fNodeManager != NULL)
if (fNodeManager != NULL) {
fNodeManager->RemoveListener(this);
fNodeManager->ReleaseReference();
}
}
@ -68,6 +75,8 @@ DebugReportGenerator::Init()
if (fNodeManager == NULL)
return B_NO_MEMORY;
fNodeManager->AddListener(this);
Run();
return B_OK;
@ -75,9 +84,9 @@ DebugReportGenerator::Init()
DebugReportGenerator*
DebugReportGenerator::Create(::Team* team)
DebugReportGenerator::Create(::Team* team, UserInterfaceListener* listener)
{
DebugReportGenerator* self = new DebugReportGenerator(team);
DebugReportGenerator* self = new DebugReportGenerator(team, listener);
try {
self->Init();
@ -145,7 +154,20 @@ DebugReportGenerator::MessageReceived(BMessage* message)
void
DebugReportGenerator::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
{
release_sem(fTeamDataSem);
if (fTraceWaitingThread == event.GetThread()) {
fTraceWaitingThread = NULL;
release_sem(fTeamDataSem);
}
}
void
DebugReportGenerator::ValueNodeValueChanged(ValueNode* node)
{
if (node == fWaitingNode) {
fWaitingNode = NULL;
release_sem(fTeamDataSem);
}
}
@ -280,6 +302,7 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
break;
locker.Unlock();
fTraceWaitingThread = thread;
status_t result = acquire_sem(fTeamDataSem);
if (result != B_OK)
return result;
@ -312,9 +335,10 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
AutoLocker<ValueNodeContainer> containerLocker(container);
for (int32 i = 0; i < container->CountChildren(); i++) {
ValueNodeChild* child = container->ChildAt(i);
_ResolveLocationIfNeeded(child, frame);
_ResolveValueIfNeeded(child->Node(), frame, 4);
UiUtils::PrintValueNodeGraph(_output, frame, child, 3, 2);
containerLocker.Unlock();
_ResolveValueIfNeeded(child->Node(), frame, 1);
containerLocker.Lock();
UiUtils::PrintValueNodeGraph(_output, frame, child, 3, 1);
}
_output << "\n";
}
@ -342,21 +366,20 @@ status_t
DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
int32 maxDepth)
{
ValueLocation* location = NULL;
Value* value = NULL;
ValueLoader loader(fTeam->GetArchitecture(), fTeam->GetTeamMemory(),
fTeam->GetTeamTypeInformation(), frame->GetCpuState());
status_t result = node->ResolvedLocationAndValue(&loader, location,
value);
node->SetLocationAndValue(location, value, result);
if (location != NULL)
location->ReleaseReference();
if (value != NULL)
value->ReleaseReference();
status_t result = B_OK;
if (node->LocationAndValueResolutionState() == VALUE_NODE_UNRESOLVED) {
fWaitingNode = node;
fListener->ValueNodeValueRequested(frame->GetCpuState(),
fNodeManager->GetContainer(), node);
result = acquire_sem(fTeamDataSem);
}
if (result == B_OK && maxDepth > 0) {
if (node->LocationAndValueResolutionState() == B_OK && maxDepth > 0) {
AutoLocker<ValueNodeContainer> containerLocker(
fNodeManager->GetContainer());
for (int32 i = 0; i < node->CountChildren(); i++) {
ValueNodeChild* child = node->ChildAt(i);
containerLocker.Unlock();
result = _ResolveLocationIfNeeded(child, frame);
if (result != B_OK)
continue;
@ -365,7 +388,15 @@ DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
if (result != B_OK)
continue;
_ResolveValueIfNeeded(child->Node(), frame, maxDepth - 1);
// since in the case of a pointer to a compound we hide
// the intervening compound, don't consider the hidden node
// a level for the purposes of depth traversal
if (node->GetType()->Kind() == TYPE_ADDRESS
&& child->GetType()->Kind() == TYPE_COMPOUND) {
_ResolveValueIfNeeded(child->Node(), frame, maxDepth);
} else
_ResolveValueIfNeeded(child->Node(), frame, maxDepth - 1);
containerLocker.Lock();
}
}

View File

@ -9,6 +9,7 @@
#include <Looper.h>
#include "Team.h"
#include "ValueNodeContainer.h"
class entry_ref;
@ -17,26 +18,32 @@ class BString;
class StackFrame;
class Team;
class Thread;
class UserInterfaceListener;
class Value;
class ValueNode;
class ValueNodeChild;
class ValueNodeManager;
class DebugReportGenerator : public BLooper, public Team::Listener {
class DebugReportGenerator : public BLooper, private Team::Listener,
private ValueNodeContainer::Listener {
public:
DebugReportGenerator(::Team* team);
DebugReportGenerator(::Team* team,
UserInterfaceListener* listener);
~DebugReportGenerator();
status_t Init();
static DebugReportGenerator* Create(::Team* team);
static DebugReportGenerator* Create(::Team* team,
UserInterfaceListener* listener);
virtual void MessageReceived(BMessage* message);
virtual void ThreadStackTraceChanged(
const Team::ThreadEvent& event);
virtual void ValueNodeValueChanged(ValueNode* node);
private:
status_t _GenerateReport(const entry_ref& outputPath);
status_t _GenerateReportHeader(BString& output);
@ -55,6 +62,9 @@ private:
Architecture* fArchitecture;
sem_id fTeamDataSem;
ValueNodeManager* fNodeManager;
UserInterfaceListener* fListener;
ValueNode* fWaitingNode;
::Thread* fTraceWaitingThread;
};
#endif // DEBUG_REPORT_GENERATOR_H

View File

@ -416,7 +416,7 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
return error;
// create the debug report generator
fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam);
fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam, this);
if (fReportGenerator == NULL)
return B_NO_MEMORY;