Rework control flow for debug report generator.

- DebugReportGenerator is now its own BLooper that generates reports asynchronously
  instead of in TeamDebugger's message loop.
- If a stack trace isn't yet available, DebugReportGenerator now waits for it to
  be generated.
- Extended Team to add a listener event for report generation completing. DebugReportGenerator
  now generates such an event when it has finished writing a report.
This commit is contained in:
Rene Gollent 2012-11-24 00:44:00 -05:00
parent 793d00f975
commit 248c2ff45c
6 changed files with 143 additions and 30 deletions

View File

@ -10,12 +10,15 @@
#include <system_revision.h> #include <system_revision.h>
#include <AutoLocker.h> #include <AutoLocker.h>
#include <Entry.h>
#include <File.h> #include <File.h>
#include <Path.h>
#include <StringForSize.h> #include <StringForSize.h>
#include "Architecture.h" #include "Architecture.h"
#include "CpuState.h" #include "CpuState.h"
#include "Image.h" #include "Image.h"
#include "MessageCodes.h"
#include "Register.h" #include "Register.h"
#include "StackFrame.h" #include "StackFrame.h"
#include "StackTrace.h" #include "StackTrace.h"
@ -27,16 +30,21 @@
DebugReportGenerator::DebugReportGenerator(::Team* team) DebugReportGenerator::DebugReportGenerator(::Team* team)
: :
BLooper("DebugReportGenerator"),
BReferenceable(), BReferenceable(),
fTeam(team), fTeam(team),
fArchitecture(team->GetArchitecture()) fArchitecture(team->GetArchitecture()),
fTeamDataSem(-1)
{ {
fTeam->AddListener(this);
fArchitecture->AcquireReference(); fArchitecture->AcquireReference();
} }
DebugReportGenerator::~DebugReportGenerator() DebugReportGenerator::~DebugReportGenerator()
{ {
fTeam->RemoveListener(this);
fArchitecture->ReleaseReference(); fArchitecture->ReleaseReference();
} }
@ -44,7 +52,12 @@ DebugReportGenerator::~DebugReportGenerator()
status_t status_t
DebugReportGenerator::Init() DebugReportGenerator::Init()
{ {
// TODO: anything needed here? fTeamDataSem = create_sem(0, "debug_controller_data_wait");
if (fTeamDataSem < B_OK)
return fTeamDataSem;
Run();
return B_OK; return B_OK;
} }
@ -66,7 +79,7 @@ DebugReportGenerator::Create(::Team* team)
status_t status_t
DebugReportGenerator::GenerateReport(const entry_ref& outputPath) DebugReportGenerator::_GenerateReport(const entry_ref& outputPath)
{ {
BFile file(&outputPath, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); BFile file(&outputPath, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
status_t result = file.InitCheck(); status_t result = file.InitCheck();
@ -90,14 +103,44 @@ DebugReportGenerator::GenerateReport(const entry_ref& outputPath)
if (result < 0) if (result < 0)
return result; return result;
BPath path(&outputPath);
fTeam->NotifyDebugReportChanged(path.Path());
return B_OK; return B_OK;
} }
void
DebugReportGenerator::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_GENERATE_DEBUG_REPORT:
{
entry_ref ref;
if (message->FindRef("target", &ref) == B_OK)
_GenerateReport(ref);
break;
}
default:
BLooper::MessageReceived(message);
break;
}
}
void
DebugReportGenerator::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
{
release_sem(fTeamDataSem);
}
status_t status_t
DebugReportGenerator::_GenerateReportHeader(BString& _output) DebugReportGenerator::_GenerateReportHeader(BString& _output)
{ {
AutoLocker<Team> locker(fTeam); AutoLocker< ::Team> locker(fTeam);
BString data; BString data;
data.SetToFormat("Debug information for team %s (%" B_PRId32 "):\n", data.SetToFormat("Debug information for team %s (%" B_PRId32 "):\n",
@ -134,7 +177,7 @@ DebugReportGenerator::_GenerateReportHeader(BString& _output)
status_t status_t
DebugReportGenerator::_DumpLoadedImages(BString& _output) DebugReportGenerator::_DumpLoadedImages(BString& _output)
{ {
AutoLocker<Team> locker(fTeam); AutoLocker< ::Team> locker(fTeam);
_output << "\nLoaded Images:\n"; _output << "\nLoaded Images:\n";
BString data; BString data;
@ -167,13 +210,13 @@ DebugReportGenerator::_DumpLoadedImages(BString& _output)
status_t status_t
DebugReportGenerator::_DumpRunningThreads(BString& _output) DebugReportGenerator::_DumpRunningThreads(BString& _output)
{ {
AutoLocker<Team> locker(fTeam); AutoLocker< ::Team> locker(fTeam);
_output << "\nActive Threads:\n"; _output << "\nActive Threads:\n";
BString data; BString data;
status_t result = B_OK; status_t result = B_OK;
for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator(); for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
Thread* thread = it.Next();) { ::Thread* thread = it.Next();) {
try { try {
data.SetToFormat("\t%s %s, id: %" B_PRId32", state: %s\n", data.SetToFormat("\t%s %s, id: %" B_PRId32", state: %s\n",
thread->Name(), thread->IsMainThread() thread->Name(), thread->IsMainThread()
@ -183,8 +226,15 @@ DebugReportGenerator::_DumpRunningThreads(BString& _output)
_output << data; _output << data;
if (thread->State() == THREAD_STATE_STOPPED) if (thread->State() == THREAD_STATE_STOPPED) {
// we need to release our lock on the team here
// since we might need to block and wait
// on the stack trace.
BReference< ::Thread> threadRef(thread);
locker.Unlock();
result = _DumpDebuggedThreadInfo(_output, thread); result = _DumpDebuggedThreadInfo(_output, thread);
locker.Lock();
}
if (result != B_OK) if (result != B_OK)
return result; return result;
} catch (...) { } catch (...) {
@ -197,14 +247,27 @@ DebugReportGenerator::_DumpRunningThreads(BString& _output)
status_t status_t
DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, Thread* thread) DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
::Thread* thread)
{ {
AutoLocker<Team> locker(fTeam); AutoLocker< ::Team> locker;
if (thread->State() != THREAD_STATE_STOPPED)
StackTrace* trace = thread->GetStackTrace();
if (trace == NULL)
return B_OK; return B_OK;
StackTrace* trace = NULL;
for (;;) {
trace = thread->GetStackTrace();
if (trace != NULL)
break;
locker.Unlock();
status_t result = acquire_sem(fTeamDataSem);
if (result != B_OK)
return result;
locker.Lock();
}
_output << "\t\tFrame\t\tIP\t\t\tFunction Name\n"; _output << "\t\tFrame\t\tIP\t\t\tFunction Name\n";
_output << "\t\t-----------------------------------------------\n"; _output << "\t\t-----------------------------------------------\n";
BString data; BString data;

View File

@ -5,8 +5,12 @@
#ifndef DEBUG_REPORT_GENERATOR_H #ifndef DEBUG_REPORT_GENERATOR_H
#define DEBUG_GENERATOR_H #define DEBUG_GENERATOR_H
#include <Looper.h>
#include <Referenceable.h> #include <Referenceable.h>
#include "Team.h"
class entry_ref; class entry_ref;
class Architecture; class Architecture;
@ -15,7 +19,8 @@ class Team;
class Thread; class Thread;
class DebugReportGenerator : public BReferenceable class DebugReportGenerator : public BLooper, public BReferenceable,
public Team::Listener
{ {
public: public:
DebugReportGenerator(::Team* team); DebugReportGenerator(::Team* team);
@ -25,18 +30,23 @@ public:
static DebugReportGenerator* Create(::Team* team); static DebugReportGenerator* Create(::Team* team);
status_t GenerateReport(const entry_ref& outputPath); virtual void MessageReceived(BMessage* message);
virtual void ThreadStackTraceChanged(
const Team::ThreadEvent& event);
private: private:
status_t _GenerateReport(const entry_ref& outputPath);
status_t _GenerateReportHeader(BString& output); status_t _GenerateReportHeader(BString& output);
status_t _DumpLoadedImages(BString& output); status_t _DumpLoadedImages(BString& output);
status_t _DumpRunningThreads(BString& output); status_t _DumpRunningThreads(BString& output);
status_t _DumpDebuggedThreadInfo(BString& output, status_t _DumpDebuggedThreadInfo(BString& output,
Thread* thread); ::Thread* thread);
private: private:
::Team* fTeam; ::Team* fTeam;
Architecture* fArchitecture; Architecture* fArchitecture;
sem_id fTeamDataSem;
}; };
#endif // DEBUG_REPORT_GENERATOR_H #endif // DEBUG_REPORT_GENERATOR_H

View File

@ -207,6 +207,8 @@ TeamDebugger::~TeamDebugger()
delete fBreakpointManager; delete fBreakpointManager;
delete fWatchpointManager; delete fWatchpointManager;
delete fMemoryBlockManager; delete fMemoryBlockManager;
fReportGenerator->Lock();
fReportGenerator->Quit();
delete fReportGenerator; delete fReportGenerator;
delete fWorker; delete fWorker;
delete fTeam; delete fTeam;
@ -550,9 +552,7 @@ TeamDebugger::MessageReceived(BMessage* message)
case MSG_GENERATE_DEBUG_REPORT: case MSG_GENERATE_DEBUG_REPORT:
{ {
entry_ref ref; fReportGenerator->PostMessage(message);
if (message->FindRef("target", &ref) == B_OK)
_HandleGenerateDebugReport(ref);
break; break;
} }
@ -1532,13 +1532,6 @@ TeamDebugger::_HandleInspectAddress(target_addr_t address,
} }
void
TeamDebugger::_HandleGenerateDebugReport(const entry_ref& ref)
{
fReportGenerator->GenerateReport(ref);
}
ThreadHandler* ThreadHandler*
TeamDebugger::_GetThreadHandler(thread_id threadID) TeamDebugger::_GetThreadHandler(thread_id threadID)
{ {

View File

@ -147,9 +147,6 @@ private:
target_addr_t address, target_addr_t address,
TeamMemoryBlock::Listener* listener); TeamMemoryBlock::Listener* listener);
void _HandleGenerateDebugReport(
const entry_ref& target);
ThreadHandler* _GetThreadHandler(thread_id threadID); ThreadHandler* _GetThreadHandler(thread_id threadID);
status_t _AddImage(const ImageInfo& imageInfo, status_t _AddImage(const ImageInfo& imageInfo,

View File

@ -635,6 +635,17 @@ Team::NotifyWatchpointChanged(Watchpoint* watchpoint)
} }
void
Team::NotifyDebugReportChanged(const char* reportPath)
{
for (ListenerList::Iterator it = fListeners.GetIterator();
Listener* listener = it.Next();) {
listener->DebugReportChanged(DebugReportEvent(
TEAM_EVENT_DEBUG_REPORT_CHANGED, this, reportPath));
}
}
void void
Team::_NotifyThreadAdded(Thread* thread) Team::_NotifyThreadAdded(Thread* thread)
{ {
@ -720,6 +731,18 @@ Team::BreakpointEvent::BreakpointEvent(uint32 type, Team* team,
} }
// #pragma mark - DebugReportEvent
Team::DebugReportEvent::DebugReportEvent(uint32 type, Team* team,
const char* reportPath)
:
Event(type, team),
fReportPath(reportPath)
{
}
// #pragma mark - WatchpointEvent // #pragma mark - WatchpointEvent
@ -834,3 +857,9 @@ void
Team::Listener::WatchpointChanged(const Team::WatchpointEvent& event) Team::Listener::WatchpointChanged(const Team::WatchpointEvent& event)
{ {
} }
void
Team::Listener::DebugReportChanged(const Team::DebugReportEvent& event)
{
}

View File

@ -38,7 +38,9 @@ enum {
TEAM_EVENT_WATCHPOINT_ADDED, TEAM_EVENT_WATCHPOINT_ADDED,
TEAM_EVENT_WATCHPOINT_REMOVED, TEAM_EVENT_WATCHPOINT_REMOVED,
TEAM_EVENT_WATCHPOINT_CHANGED TEAM_EVENT_WATCHPOINT_CHANGED,
TEAM_EVENT_DEBUG_REPORT_CHANGED
}; };
@ -61,6 +63,7 @@ class Team {
public: public:
class Event; class Event;
class BreakpointEvent; class BreakpointEvent;
class DebugReportEvent;
class ImageEvent; class ImageEvent;
class ThreadEvent; class ThreadEvent;
class UserBreakpointEvent; class UserBreakpointEvent;
@ -183,6 +186,10 @@ public:
void NotifyWatchpointChanged( void NotifyWatchpointChanged(
Watchpoint* watchpoint); Watchpoint* watchpoint);
// debug report related service methods
void NotifyDebugReportChanged(
const char* reportPath);
private: private:
struct BreakpointByAddressPredicate; struct BreakpointByAddressPredicate;
struct WatchpointByAddressPredicate; struct WatchpointByAddressPredicate;
@ -261,6 +268,17 @@ protected:
}; };
class Team::DebugReportEvent : public Event {
public:
DebugReportEvent(uint32 type, Team* team,
const char* reportPath);
const char* GetReportPath() const { return fReportPath; }
protected:
const char* fReportPath;
};
class Team::WatchpointEvent : public Event { class Team::WatchpointEvent : public Event {
public: public:
WatchpointEvent(uint32 type, Team* team, WatchpointEvent(uint32 type, Team* team,
@ -318,6 +336,9 @@ public:
const Team::WatchpointEvent& event); const Team::WatchpointEvent& event);
virtual void WatchpointChanged( virtual void WatchpointChanged(
const Team::WatchpointEvent& event); const Team::WatchpointEvent& event);
virtual void DebugReportChanged(
const Team::DebugReportEvent& event);
}; };