diff --git a/src/apps/debugger/Debugger.cpp b/src/apps/debugger/Debugger.cpp index 7ac697c571..253a99e2ba 100644 --- a/src/apps/debugger/Debugger.cpp +++ b/src/apps/debugger/Debugger.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include "debug_utils.h" @@ -163,11 +164,12 @@ parse_arguments(int argc, const char* const* argv, bool noOutput, } -class Debugger : public BApplication { +class Debugger : public BApplication, private TeamDebugger::Listener { public: Debugger() : - BApplication(kDebuggerSignature) + BApplication(kDebuggerSignature), + fRunningTeamDebuggers(0) { } @@ -178,17 +180,14 @@ public: virtual void MessageReceived(BMessage* message) { switch (message->what) { - case MSG_DEBUGGER_QUIT_REQUESTED: + case MSG_TEAM_DEBUGGER_QUIT: { - TeamDebugger* debugger = NULL; - if (message->FindPointer("debugger", - (void**)&debugger) == B_OK - && fTeamDebuggers.HasItem(debugger)) { - fTeamDebuggers.RemoveItem(debugger); - debugger->DeleteSelf(); - if (fTeamDebuggers.CountItems() == 0) - PostMessage(B_QUIT_REQUESTED); - } + int32 threadID; + if (message->FindInt32("thread", &threadID) == B_OK) + wait_for_thread(threadID, NULL); + + if (--fRunningTeamDebuggers == 0) + Quit(); break; } default: @@ -255,23 +254,45 @@ printf("There's already a debugger for team: %ld\n", team); return; } - debugger = new(std::nothrow) TeamDebugger; + debugger = new(std::nothrow) TeamDebugger(this); if (debugger == NULL) { // TODO: Notify the user! fprintf(stderr, "Error: Out of memory!\n"); } - if (debugger->Init(team, thread, stopInMain) == B_OK - && fTeamDebuggers.AddItem(debugger)) { + status_t error = debugger->Init(team, thread, stopInMain); + if (debugger->Thread()) + fRunningTeamDebuggers++; + + if (error == B_OK && fTeamDebuggers.AddItem(debugger)) { printf("debugger for team %ld created and initialized successfully!\n", team); } else delete debugger; } +private: + typedef BObjectList TeamDebuggerList; + +private: + // TeamDebugger::Listener + virtual void TeamDebuggerQuit(TeamDebugger* debugger) + { + // Note: Locking here only works, since we're never locking the other + // way around. If we even need to do that, we'll have to introduce a + // separate lock to protect the list. + AutoLocker locker(this); + fTeamDebuggers.RemoveItem(debugger); + locker.Unlock(); + + if (debugger->Thread() >= 0) { + BMessage message(MSG_TEAM_DEBUGGER_QUIT); + message.AddInt32("thread", debugger->Thread()); + PostMessage(&message); + } + } + virtual bool QuitRequested() { - // TODO:... -// return true; // NOTE: The default implementation will just ask all windows' // QuitRequested() hooks. This in turn will ask the TeamWindows. // For now, this is what we want. If we have more windows later, @@ -282,12 +303,17 @@ printf("debugger for team %ld created and initialized successfully!\n", team); // QuitReqested() hook or the TeamsWindow and other global windows // could always return false in their QuitRequested(). return BApplication::QuitRequested(); + // TODO: This is ugly. The team debuggers own the windows, not the + // other way around. } -private: - typedef BObjectList TeamDebuggerList; + virtual void Quit() + { + // don't quit before all team debuggers have been quit + if (fRunningTeamDebuggers <= 0) + BApplication::Quit(); + } -private: TeamDebugger* _TeamDebuggerForTeam(team_id teamID) const { for (int32 i = 0; TeamDebugger* debugger = fTeamDebuggers.ItemAt(i); @@ -301,6 +327,7 @@ private: private: TeamDebuggerList fTeamDebuggers; + int32 fRunningTeamDebuggers; }; diff --git a/src/apps/debugger/MessageCodes.h b/src/apps/debugger/MessageCodes.h index 8e7661a6d0..05367b0ce9 100644 --- a/src/apps/debugger/MessageCodes.h +++ b/src/apps/debugger/MessageCodes.h @@ -21,7 +21,7 @@ enum { MSG_STACK_FRAME_SOURCE_CODE_CHANGED = 'sfsc', MSG_USER_BREAKPOINT_CHANGED = 'ubrc', - MSG_DEBUGGER_QUIT_REQUESTED = 'dbqt' + MSG_TEAM_DEBUGGER_QUIT = 'dbqt' }; diff --git a/src/apps/debugger/TeamDebugger.cpp b/src/apps/debugger/TeamDebugger.cpp index 730632ffbe..ef3ae426bd 100644 --- a/src/apps/debugger/TeamDebugger.cpp +++ b/src/apps/debugger/TeamDebugger.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -26,9 +25,10 @@ #include "TeamDebugModel.h" -TeamDebugger::TeamDebugger() +TeamDebugger::TeamDebugger(Listener* listener) : BLooper("team debugger"), + fListener(listener), fTeam(NULL), fDebugModel(NULL), fTeamID(-1), @@ -63,6 +63,8 @@ TeamDebugger::~TeamDebugger() delete fWorker; delete fDebugModel; delete fTeam; + + fListener->TeamDebuggerQuit(this); } @@ -188,14 +190,6 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain) } -void -TeamDebugger::DeleteSelf() -{ - Lock(); - Quit(); -} - - void TeamDebugger::MessageReceived(BMessage* message) { @@ -323,13 +317,9 @@ TeamDebugger::ClearBreakpointRequested(target_addr_t address) bool TeamDebugger::TeamWindowQuitRequested(TeamWindow* window) { - // TODO: Is this what shall happen? - if (!fTeam->Lock()) - return true; - + AutoLocker< ::Team> locker(fTeam); BString name(fTeam->Name()); - - fTeam->Unlock(); + locker.Unlock(); BString message; message << "What shall be done about the debugged team '"; @@ -354,14 +344,11 @@ TeamDebugger::TeamWindowQuitRequested(TeamWindow* window) case 1: return false; case 2: - // Detach from the team and resume and stopped threads. Seems to be - // the default action anyways. + // Detach from the team and resume and stopped threads. break; } - BMessage quitMessage(MSG_DEBUGGER_QUIT_REQUESTED); - quitMessage.AddPointer("debugger", this); - be_app->PostMessage(&quitMessage); + PostMessage(B_QUIT_REQUESTED); return true; } @@ -891,3 +878,11 @@ TeamDebugger::_NotifyUser(const char* title, const char* text,...) // create it and don't care anymore. Maybe an error window, which can // display a list of errors would be the better choice. } + + +// #pragma mark - Listener + + +TeamDebugger::Listener::~Listener() +{ +} diff --git a/src/apps/debugger/TeamDebugger.h b/src/apps/debugger/TeamDebugger.h index fe77f3b645..97170472a5 100644 --- a/src/apps/debugger/TeamDebugger.h +++ b/src/apps/debugger/TeamDebugger.h @@ -20,10 +20,13 @@ class DebuggerInterface; class TeamDebugModel; -class TeamDebugger : private BLooper, private TeamWindow::Listener, +class TeamDebugger : public BLooper, private TeamWindow::Listener, private JobListener, private Team::Listener { public: - TeamDebugger(); + class Listener; + +public: + TeamDebugger(Listener* listener); ~TeamDebugger(); status_t Init(team_id teamID, thread_id threadID, @@ -31,11 +34,9 @@ public: team_id TeamID() const { return fTeamID; } - void DeleteSelf(); - -private: virtual void MessageReceived(BMessage* message); +private: // TeamWindow::Listener virtual void StackFrameSourceCodeRequested( TeamWindow* window, StackFrame* frame); @@ -111,6 +112,7 @@ private: const char* text,...); private: + Listener* fListener; ::Team* fTeam; TeamDebugModel* fDebugModel; team_id fTeamID; @@ -123,4 +125,13 @@ private: bool fKillTeamOnQuit; }; + +class TeamDebugger::Listener { +public: + virtual ~Listener(); + + virtual void TeamDebuggerQuit(TeamDebugger* debugger) = 0; +}; + + #endif // TEAM_DEBUGGER_H