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:
@@ -28,6 +28,7 @@
|
|||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "Type.h"
|
#include "Type.h"
|
||||||
#include "UiUtils.h"
|
#include "UiUtils.h"
|
||||||
|
#include "UserInterface.h"
|
||||||
#include "Value.h"
|
#include "Value.h"
|
||||||
#include "ValueLoader.h"
|
#include "ValueLoader.h"
|
||||||
#include "ValueLocation.h"
|
#include "ValueLocation.h"
|
||||||
@@ -35,13 +36,17 @@
|
|||||||
#include "ValueNodeManager.h"
|
#include "ValueNodeManager.h"
|
||||||
|
|
||||||
|
|
||||||
DebugReportGenerator::DebugReportGenerator(::Team* team)
|
DebugReportGenerator::DebugReportGenerator(::Team* team,
|
||||||
|
UserInterfaceListener* listener)
|
||||||
:
|
:
|
||||||
BLooper("DebugReportGenerator"),
|
BLooper("DebugReportGenerator"),
|
||||||
fTeam(team),
|
fTeam(team),
|
||||||
fArchitecture(team->GetArchitecture()),
|
fArchitecture(team->GetArchitecture()),
|
||||||
fTeamDataSem(-1),
|
fTeamDataSem(-1),
|
||||||
fNodeManager(NULL)
|
fNodeManager(NULL),
|
||||||
|
fListener(listener),
|
||||||
|
fWaitingNode(NULL),
|
||||||
|
fTraceWaitingThread(NULL)
|
||||||
{
|
{
|
||||||
fTeam->AddListener(this);
|
fTeam->AddListener(this);
|
||||||
fArchitecture->AcquireReference();
|
fArchitecture->AcquireReference();
|
||||||
@@ -52,8 +57,10 @@ DebugReportGenerator::~DebugReportGenerator()
|
|||||||
{
|
{
|
||||||
fTeam->RemoveListener(this);
|
fTeam->RemoveListener(this);
|
||||||
fArchitecture->ReleaseReference();
|
fArchitecture->ReleaseReference();
|
||||||
if (fNodeManager != NULL)
|
if (fNodeManager != NULL) {
|
||||||
|
fNodeManager->RemoveListener(this);
|
||||||
fNodeManager->ReleaseReference();
|
fNodeManager->ReleaseReference();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -68,6 +75,8 @@ DebugReportGenerator::Init()
|
|||||||
if (fNodeManager == NULL)
|
if (fNodeManager == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fNodeManager->AddListener(this);
|
||||||
|
|
||||||
Run();
|
Run();
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -75,9 +84,9 @@ DebugReportGenerator::Init()
|
|||||||
|
|
||||||
|
|
||||||
DebugReportGenerator*
|
DebugReportGenerator*
|
||||||
DebugReportGenerator::Create(::Team* team)
|
DebugReportGenerator::Create(::Team* team, UserInterfaceListener* listener)
|
||||||
{
|
{
|
||||||
DebugReportGenerator* self = new DebugReportGenerator(team);
|
DebugReportGenerator* self = new DebugReportGenerator(team, listener);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
self->Init();
|
self->Init();
|
||||||
@@ -145,7 +154,20 @@ DebugReportGenerator::MessageReceived(BMessage* message)
|
|||||||
void
|
void
|
||||||
DebugReportGenerator::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
|
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;
|
break;
|
||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
fTraceWaitingThread = thread;
|
||||||
status_t result = acquire_sem(fTeamDataSem);
|
status_t result = acquire_sem(fTeamDataSem);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
@@ -312,9 +335,10 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
|
|||||||
AutoLocker<ValueNodeContainer> containerLocker(container);
|
AutoLocker<ValueNodeContainer> containerLocker(container);
|
||||||
for (int32 i = 0; i < container->CountChildren(); i++) {
|
for (int32 i = 0; i < container->CountChildren(); i++) {
|
||||||
ValueNodeChild* child = container->ChildAt(i);
|
ValueNodeChild* child = container->ChildAt(i);
|
||||||
_ResolveLocationIfNeeded(child, frame);
|
containerLocker.Unlock();
|
||||||
_ResolveValueIfNeeded(child->Node(), frame, 4);
|
_ResolveValueIfNeeded(child->Node(), frame, 1);
|
||||||
UiUtils::PrintValueNodeGraph(_output, frame, child, 3, 2);
|
containerLocker.Lock();
|
||||||
|
UiUtils::PrintValueNodeGraph(_output, frame, child, 3, 1);
|
||||||
}
|
}
|
||||||
_output << "\n";
|
_output << "\n";
|
||||||
}
|
}
|
||||||
@@ -342,21 +366,20 @@ status_t
|
|||||||
DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
||||||
int32 maxDepth)
|
int32 maxDepth)
|
||||||
{
|
{
|
||||||
ValueLocation* location = NULL;
|
status_t result = B_OK;
|
||||||
Value* value = NULL;
|
if (node->LocationAndValueResolutionState() == VALUE_NODE_UNRESOLVED) {
|
||||||
ValueLoader loader(fTeam->GetArchitecture(), fTeam->GetTeamMemory(),
|
fWaitingNode = node;
|
||||||
fTeam->GetTeamTypeInformation(), frame->GetCpuState());
|
fListener->ValueNodeValueRequested(frame->GetCpuState(),
|
||||||
status_t result = node->ResolvedLocationAndValue(&loader, location,
|
fNodeManager->GetContainer(), node);
|
||||||
value);
|
result = acquire_sem(fTeamDataSem);
|
||||||
node->SetLocationAndValue(location, value, result);
|
}
|
||||||
if (location != NULL)
|
|
||||||
location->ReleaseReference();
|
|
||||||
if (value != NULL)
|
|
||||||
value->ReleaseReference();
|
|
||||||
|
|
||||||
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++) {
|
for (int32 i = 0; i < node->CountChildren(); i++) {
|
||||||
ValueNodeChild* child = node->ChildAt(i);
|
ValueNodeChild* child = node->ChildAt(i);
|
||||||
|
containerLocker.Unlock();
|
||||||
result = _ResolveLocationIfNeeded(child, frame);
|
result = _ResolveLocationIfNeeded(child, frame);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
continue;
|
continue;
|
||||||
@@ -365,7 +388,15 @@ DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
|||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
continue;
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <Looper.h>
|
#include <Looper.h>
|
||||||
|
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
#include "ValueNodeContainer.h"
|
||||||
|
|
||||||
|
|
||||||
class entry_ref;
|
class entry_ref;
|
||||||
@@ -17,26 +18,32 @@ class BString;
|
|||||||
class StackFrame;
|
class StackFrame;
|
||||||
class Team;
|
class Team;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
class UserInterfaceListener;
|
||||||
class Value;
|
class Value;
|
||||||
class ValueNode;
|
class ValueNode;
|
||||||
class ValueNodeChild;
|
class ValueNodeChild;
|
||||||
class ValueNodeManager;
|
class ValueNodeManager;
|
||||||
|
|
||||||
|
|
||||||
class DebugReportGenerator : public BLooper, public Team::Listener {
|
class DebugReportGenerator : public BLooper, private Team::Listener,
|
||||||
|
private ValueNodeContainer::Listener {
|
||||||
public:
|
public:
|
||||||
DebugReportGenerator(::Team* team);
|
DebugReportGenerator(::Team* team,
|
||||||
|
UserInterfaceListener* listener);
|
||||||
~DebugReportGenerator();
|
~DebugReportGenerator();
|
||||||
|
|
||||||
status_t Init();
|
status_t Init();
|
||||||
|
|
||||||
static DebugReportGenerator* Create(::Team* team);
|
static DebugReportGenerator* Create(::Team* team,
|
||||||
|
UserInterfaceListener* listener);
|
||||||
|
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
virtual void ThreadStackTraceChanged(
|
virtual void ThreadStackTraceChanged(
|
||||||
const Team::ThreadEvent& event);
|
const Team::ThreadEvent& event);
|
||||||
|
|
||||||
|
virtual void ValueNodeValueChanged(ValueNode* node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _GenerateReport(const entry_ref& outputPath);
|
status_t _GenerateReport(const entry_ref& outputPath);
|
||||||
status_t _GenerateReportHeader(BString& output);
|
status_t _GenerateReportHeader(BString& output);
|
||||||
@@ -55,6 +62,9 @@ private:
|
|||||||
Architecture* fArchitecture;
|
Architecture* fArchitecture;
|
||||||
sem_id fTeamDataSem;
|
sem_id fTeamDataSem;
|
||||||
ValueNodeManager* fNodeManager;
|
ValueNodeManager* fNodeManager;
|
||||||
|
UserInterfaceListener* fListener;
|
||||||
|
ValueNode* fWaitingNode;
|
||||||
|
::Thread* fTraceWaitingThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEBUG_REPORT_GENERATOR_H
|
#endif // DEBUG_REPORT_GENERATOR_H
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
// create the debug report generator
|
// create the debug report generator
|
||||||
fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam);
|
fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam, this);
|
||||||
if (fReportGenerator == NULL)
|
if (fReportGenerator == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user