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:
parent
793d00f975
commit
248c2ff45c
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user