From 248c2ff45ca8253a2bd6114a358bc6e5ac4d2026 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Sat, 24 Nov 2012 00:44:00 -0500 Subject: [PATCH] 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. --- .../controllers/DebugReportGenerator.cpp | 89 ++++++++++++++++--- .../controllers/DebugReportGenerator.h | 16 +++- .../debugger/controllers/TeamDebugger.cpp | 13 +-- src/apps/debugger/controllers/TeamDebugger.h | 3 - src/apps/debugger/model/Team.cpp | 29 ++++++ src/apps/debugger/model/Team.h | 23 ++++- 6 files changed, 143 insertions(+), 30 deletions(-) diff --git a/src/apps/debugger/controllers/DebugReportGenerator.cpp b/src/apps/debugger/controllers/DebugReportGenerator.cpp index 82f9d52e10..2185af1cb9 100644 --- a/src/apps/debugger/controllers/DebugReportGenerator.cpp +++ b/src/apps/debugger/controllers/DebugReportGenerator.cpp @@ -10,12 +10,15 @@ #include #include +#include #include +#include #include #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 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 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 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 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; diff --git a/src/apps/debugger/controllers/DebugReportGenerator.h b/src/apps/debugger/controllers/DebugReportGenerator.h index a05ac5925b..1267586aee 100644 --- a/src/apps/debugger/controllers/DebugReportGenerator.h +++ b/src/apps/debugger/controllers/DebugReportGenerator.h @@ -5,8 +5,12 @@ #ifndef DEBUG_REPORT_GENERATOR_H #define DEBUG_GENERATOR_H + +#include #include +#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 diff --git a/src/apps/debugger/controllers/TeamDebugger.cpp b/src/apps/debugger/controllers/TeamDebugger.cpp index d0865ec68c..923f3d37e0 100644 --- a/src/apps/debugger/controllers/TeamDebugger.cpp +++ b/src/apps/debugger/controllers/TeamDebugger.cpp @@ -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) { diff --git a/src/apps/debugger/controllers/TeamDebugger.h b/src/apps/debugger/controllers/TeamDebugger.h index 8607aae119..378038b4bb 100644 --- a/src/apps/debugger/controllers/TeamDebugger.h +++ b/src/apps/debugger/controllers/TeamDebugger.h @@ -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, diff --git a/src/apps/debugger/model/Team.cpp b/src/apps/debugger/model/Team.cpp index 0f3a6a240a..af38083a0d 100644 --- a/src/apps/debugger/model/Team.cpp +++ b/src/apps/debugger/model/Team.cpp @@ -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) +{ +} diff --git a/src/apps/debugger/model/Team.h b/src/apps/debugger/model/Team.h index d11e76728f..4b89c02c21 100644 --- a/src/apps/debugger/model/Team.h +++ b/src/apps/debugger/model/Team.h @@ -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); };