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 <AutoLocker.h>
#include <Entry.h>
#include <File.h>
#include <Path.h>
#include <StringForSize.h>
#include "Architecture.h"
#include "CpuState.h"
#include "Image.h"
#include "MessageCodes.h"
#include "Register.h"
#include "StackFrame.h"
#include "StackTrace.h"
@ -27,16 +30,21 @@
DebugReportGenerator::DebugReportGenerator(::Team* team)
:
BLooper("DebugReportGenerator"),
BReferenceable(),
fTeam(team),
fArchitecture(team->GetArchitecture())
fArchitecture(team->GetArchitecture()),
fTeamDataSem(-1)
{
fTeam->AddListener(this);
fArchitecture->AcquireReference();
}
DebugReportGenerator::~DebugReportGenerator()
{
fTeam->RemoveListener(this);
fArchitecture->ReleaseReference();
}
@ -44,7 +52,12 @@ DebugReportGenerator::~DebugReportGenerator()
status_t
DebugReportGenerator::Init()
{
// TODO: anything needed here?
fTeamDataSem = create_sem(0, "debug_controller_data_wait");
if (fTeamDataSem < B_OK)
return fTeamDataSem;
Run();
return B_OK;
}
@ -66,7 +79,7 @@ DebugReportGenerator::Create(::Team* team)
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);
status_t result = file.InitCheck();
@ -90,14 +103,44 @@ DebugReportGenerator::GenerateReport(const entry_ref& outputPath)
if (result < 0)
return result;
BPath path(&outputPath);
fTeam->NotifyDebugReportChanged(path.Path());
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
DebugReportGenerator::_GenerateReportHeader(BString& _output)
{
AutoLocker<Team> locker(fTeam);
AutoLocker< ::Team> locker(fTeam);
BString data;
data.SetToFormat("Debug information for team %s (%" B_PRId32 "):\n",
@ -134,7 +177,7 @@ DebugReportGenerator::_GenerateReportHeader(BString& _output)
status_t
DebugReportGenerator::_DumpLoadedImages(BString& _output)
{
AutoLocker<Team> locker(fTeam);
AutoLocker< ::Team> locker(fTeam);
_output << "\nLoaded Images:\n";
BString data;
@ -167,13 +210,13 @@ DebugReportGenerator::_DumpLoadedImages(BString& _output)
status_t
DebugReportGenerator::_DumpRunningThreads(BString& _output)
{
AutoLocker<Team> locker(fTeam);
AutoLocker< ::Team> locker(fTeam);
_output << "\nActive Threads:\n";
BString data;
status_t result = B_OK;
for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
Thread* thread = it.Next();) {
::Thread* thread = it.Next();) {
try {
data.SetToFormat("\t%s %s, id: %" B_PRId32", state: %s\n",
thread->Name(), thread->IsMainThread()
@ -183,8 +226,15 @@ DebugReportGenerator::_DumpRunningThreads(BString& _output)
_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);
locker.Lock();
}
if (result != B_OK)
return result;
} catch (...) {
@ -197,14 +247,27 @@ DebugReportGenerator::_DumpRunningThreads(BString& _output)
status_t
DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, Thread* thread)
DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
::Thread* thread)
{
AutoLocker<Team> locker(fTeam);
StackTrace* trace = thread->GetStackTrace();
if (trace == NULL)
AutoLocker< ::Team> locker;
if (thread->State() != THREAD_STATE_STOPPED)
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\t-----------------------------------------------\n";
BString data;

View File

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

View File

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

View File

@ -147,9 +147,6 @@ private:
target_addr_t address,
TeamMemoryBlock::Listener* listener);
void _HandleGenerateDebugReport(
const entry_ref& target);
ThreadHandler* _GetThreadHandler(thread_id threadID);
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
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
@ -834,3 +857,9 @@ void
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_REMOVED,
TEAM_EVENT_WATCHPOINT_CHANGED
TEAM_EVENT_WATCHPOINT_CHANGED,
TEAM_EVENT_DEBUG_REPORT_CHANGED
};
@ -61,6 +63,7 @@ class Team {
public:
class Event;
class BreakpointEvent;
class DebugReportEvent;
class ImageEvent;
class ThreadEvent;
class UserBreakpointEvent;
@ -183,6 +186,10 @@ public:
void NotifyWatchpointChanged(
Watchpoint* watchpoint);
// debug report related service methods
void NotifyDebugReportChanged(
const char* reportPath);
private:
struct BreakpointByAddressPredicate;
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 {
public:
WatchpointEvent(uint32 type, Team* team,
@ -318,6 +336,9 @@ public:
const Team::WatchpointEvent& event);
virtual void WatchpointChanged(
const Team::WatchpointEvent& event);
virtual void DebugReportChanged(
const Team::DebugReportEvent& event);
};