From a1afac4dcaf2c46b261a0aa1fc5117f9d2f0cc61 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Wed, 20 Apr 2016 19:23:01 -0400 Subject: [PATCH] Debugger: Rework to fully use TargetHostInterface. Application objects: - Rework and simplify to take into account that they will no longer be directly managing the team debugger list. Requests to start a new debugger are still funnelled through here however, and as such, said requests must now provide the appropriate target host to start with. Adjust StartTeamWindow and TeamsWindow accordingly. - On global init, always create an instance of the local interface. TargetHostInterface: - Convert to BLooper and implement TeamDebugger's Listener interface. TargetHostInterfaces now directly manage their TeamDebugger instances, and consequently take over the equivalent duties that the main application previously had. - Adjust signatures of Attach/CreateTeam to add const. Adjust LocalTargetHostInterface accordingly. - Add accessor to determine if a given interface is local or not. Will be needed for the TeamDebugger's file manager eventually so it knows if it needs to request remote files if no matching local file is found. - Add accessor to start a TeamDebugger instance, and corresponding options structure. TargetHostInterfaceRoster: - Minor adjustments to host interface initialization to take into account needing to start the looper. - Add accessor for number of running team debuggers, for the main app to use when deciding to quit. TeamDebugger: - Add accessor for SettingsManager. Needed for the case of a restart request, as the host interfaces do not have direct access to it. TeamsWindow: - For now, always grab the local host interface when initializing the window. Once the remote interface is implemented, this will need to be adjusted, but the appropriate UI for creating/selecting it is needed first anyways. With these changes, the main application is fully host-agnostic, and all management of actual debuggers is delegated to their parent host interfaces. There still needs to be a listener interface for the host interface and/or roster though, so that the application can be made aware of when debuggers quit, as this drives whether it's time to terminate the app or not. --- src/apps/debugger/Debugger.cpp | 437 +++++---------------- src/apps/debugger/controllers/TeamDebugger.h | 2 + .../target_host_interface/TargetHostInterface.cpp | 190 ++++++++- .../target_host_interface/TargetHostInterface.h | 47 ++- .../TargetHostInterfaceRoster.cpp | 19 +- .../TargetHostInterfaceRoster.h | 2 + .../local/LocalTargetHostInterface.cpp | 29 +- .../local/LocalTargetHostInterface.h | 8 +- .../local/LocalTargetHostInterfaceInfo.cpp | 7 +- .../gui/teams_window/TeamsListView.cpp | 2 - .../gui/teams_window/TeamsWindow.cpp | 22 +- .../gui/utility_windows/StartTeamWindow.cpp | 12 +- .../gui/utility_windows/StartTeamWindow.h | 9 +- 13 files changed, 405 insertions(+), 381 deletions(-) diff --git a/src/apps/debugger/Debugger.cpp b/src/apps/debugger/Debugger.cpp index 5d2773edaa..a23de964a6 100644 --- a/src/apps/debugger/Debugger.cpp +++ b/src/apps/debugger/Debugger.cpp @@ -20,10 +20,8 @@ #include #include -#include "debug_utils.h" - #include "CommandLineUserInterface.h" -#include "LocalDebuggerInterface.h" +#include "DebuggerInterface.h" #include "GraphicalUserInterface.h" #include "ImageDebugLoadingStateHandlerRoster.h" #include "MessageCodes.h" @@ -31,6 +29,8 @@ #include "SettingsManager.h" #include "SignalSet.h" #include "StartTeamWindow.h" +#include "TargetHostInterface.h" +#include "TargetHostInterfaceRoster.h" #include "TeamDebugger.h" #include "TeamsWindow.h" #include "TypeHandlerRoster.h" @@ -101,13 +101,16 @@ struct Options { }; -struct DebuggedProgramInfo { - team_id team; - thread_id thread; - int commandLineArgc; - const char* const* commandLineArgv; - bool stopInMain; -}; +static void +set_debugger_options_from_options(TeamDebuggerOptions& _debuggerOptions, + const Options& options) +{ + _debuggerOptions.commandLineArgc = options.commandLineArgc; + _debuggerOptions.commandLineArgv = options.commandLineArgv; + _debuggerOptions.team = options.team; + _debuggerOptions.thread = options.thread; +} + static bool @@ -219,136 +222,27 @@ global_init() if (error != B_OK) return error; - return B_OK; -} - - -/** - * Finds or runs the program to debug, depending on the command line options. - * @param options The parsed command line options. - * @param _info The info for the program to fill in. Will only be filled in - * if successful. - * @return \c true, if the program has been found or ran. - */ -static bool -get_debugged_program(const Options& options, DebuggedProgramInfo& _info) -{ - team_id team = options.team; - thread_id thread = options.thread; - bool stopInMain = false; - - // If command line arguments were given, start the program. - if (options.commandLineArgc > 0) { - printf("loading program: \"%s\" ...\n", options.commandLineArgv[0]); - // TODO: What about the CWD? - thread = load_program(options.commandLineArgv, - options.commandLineArgc, false); - if (thread < 0) { - // TODO: Notify the user! - fprintf(stderr, "Error: Failed to load program \"%s\": %s\n", - options.commandLineArgv[0], strerror(thread)); - return false; - } - - team = thread; - // main thread ID == team ID - stopInMain = true; - } - - // no parameters given, prompt the user to attach to a team - if (team < 0 && thread < 0) - return false; - - // no team, but a thread -- get team - if (team < 0) { - printf("no team yet, getting thread info...\n"); - thread_info threadInfo; - status_t error = get_thread_info(thread, &threadInfo); - if (error != B_OK) { - // TODO: Notify the user! - fprintf(stderr, "Error: Failed to get info for thread \"%" B_PRId32 - "\": %s\n", thread, strerror(error)); - return false; - } - - team = threadInfo.team; - } - printf("team: %" B_PRId32 ", thread: %" B_PRId32 "\n", team, thread); - - _info.commandLineArgc = options.commandLineArgc; - _info.commandLineArgv = options.commandLineArgv; - _info.team = team; - _info.thread = thread; - _info.stopInMain = stopInMain; - return true; -} - - -/** - * Creates a TeamDebugger for the given team. If userInterface is given, - * that user interface is used (the caller retains its reference), otherwise - * a graphical user interface is created. - */ -static TeamDebugger* -start_team_debugger(team_id teamID, SettingsManager* settingsManager, - TeamDebugger::Listener* listener, thread_id threadID = -1, - int commandLineArgc = 0, const char* const* commandLineArgv = NULL, - bool stopInMain = false, UserInterface* userInterface = NULL, - status_t* _result = NULL) -{ - if (teamID < 0) - return NULL; - - BReference userInterfaceReference; - if (userInterface == NULL) { - userInterface = new(std::nothrow) GraphicalUserInterface; - if (userInterface == NULL) { - // TODO: Notify the user! - fprintf(stderr, "Error: Out of memory!\n"); - return NULL; - } - - userInterfaceReference.SetTo(userInterface, true); - } - - BReference interfaceReference; - DebuggerInterface* debuggerInterface - = new(std::nothrow) LocalDebuggerInterface(teamID); - if (debuggerInterface == NULL) - return NULL; - interfaceReference.SetTo(debuggerInterface, true); - - if (debuggerInterface->Init() != B_OK) - return NULL; - - status_t error = B_NO_MEMORY; + error = TargetHostInterfaceRoster::CreateDefault(); + if (error != B_OK) + return error; - TeamDebugger* debugger = new(std::nothrow) TeamDebugger(listener, - userInterface, settingsManager); - if (debugger != NULL) { - error = debugger->Init(debuggerInterface, threadID, commandLineArgc, - commandLineArgv, stopInMain); - } + // for now, always create an instance of the local interface + // by default + TargetHostInterface* hostInterface; + TargetHostInterfaceRoster* roster = TargetHostInterfaceRoster::Default(); + error = roster->CreateInterface(roster->InterfaceInfoAt(0), NULL, + hostInterface); + if (error != B_OK) + return error; - if (error != B_OK) { - printf("Error: debugger for team %" B_PRId32 " failed to init: %s!\n", - teamID, strerror(error)); - delete debugger; - debugger = NULL; - } else - printf("debugger for team %" B_PRId32 " created and initialized " - "successfully!\n", teamID); - - if (_result != NULL) - *_result = error; - return debugger; + return B_OK; } // #pragma mark - Debugger application class -class Debugger : public BApplication, private TeamDebugger::Listener { +class Debugger : public BApplication { public: Debugger(); ~Debugger(); @@ -359,27 +253,15 @@ public: virtual void ArgvReceived(int32 argc, char** argv); private: - typedef BObjectList TeamDebuggerList; - -private: - // TeamDebugger::Listener - virtual void TeamDebuggerStarted(TeamDebugger* debugger); - virtual void TeamDebuggerRestartRequested( - TeamDebugger* debugger); - virtual void TeamDebuggerQuit(TeamDebugger* debugger); - virtual bool QuitRequested(); virtual void Quit(); - TeamDebugger* _FindTeamDebugger(team_id teamID) const; - - status_t _StartNewTeam(const char* path, const char* args); - status_t _StartOrFindTeam(Options& options); +private: + status_t _StartNewTeam(TargetHostInterface* interface, + const char* teamPath, const char* args); private: SettingsManager fSettingsManager; - TeamDebuggerList fTeamDebuggers; - int32 fRunningTeamDebuggers; TeamsWindow* fTeamsWindow; StartTeamWindow* fStartTeamWindow; }; @@ -388,34 +270,20 @@ private: // #pragma mark - CliDebugger -class CliDebugger : private TeamDebugger::Listener { +class CliDebugger { public: CliDebugger(); ~CliDebugger(); bool Run(const Options& options); - -private: - // TeamDebugger::Listener - virtual void TeamDebuggerStarted(TeamDebugger* debugger); - virtual void TeamDebuggerRestartRequested( - TeamDebugger* debugger); - virtual void TeamDebuggerQuit(TeamDebugger* debugger); }; -class ReportDebugger : private TeamDebugger::Listener { +class ReportDebugger { public: ReportDebugger(); ~ReportDebugger(); bool Run(const Options& options); - -private: - // TeamDebugger::Listener - virtual void TeamDebuggerStarted(TeamDebugger* debugger); - virtual void TeamDebuggerRestartRequested( - TeamDebugger* debugger); - virtual void TeamDebuggerQuit(TeamDebugger* debugger); }; @@ -425,7 +293,6 @@ private: Debugger::Debugger() : BApplication(kDebuggerSignature), - fRunningTeamDebuggers(0), fTeamsWindow(NULL), fStartTeamWindow(NULL) { @@ -437,6 +304,7 @@ Debugger::~Debugger() ValueHandlerRoster::DeleteDefault(); TypeHandlerRoster::DeleteDefault(); ImageDebugLoadingStateHandlerRoster::DeleteDefault(); + TargetHostInterfaceRoster::DeleteDefault(); } @@ -480,9 +348,14 @@ Debugger::MessageReceived(BMessage* message) } case MSG_SHOW_START_TEAM_WINDOW: { + TargetHostInterface* hostInterface; + if (message->FindPointer("interface", + reinterpret_cast(&hostInterface)) != B_OK) { + break; + } BMessenger messenger(fStartTeamWindow); if (!messenger.IsValid()) { - fStartTeamWindow = StartTeamWindow::Create(); + fStartTeamWindow = StartTeamWindow::Create(hostInterface); if (fStartTeamWindow == NULL) break; fStartTeamWindow->Show(); @@ -497,56 +370,45 @@ Debugger::MessageReceived(BMessage* message) } case MSG_DEBUG_THIS_TEAM: { - int32 teamID; + team_id teamID; if (message->FindInt32("team", &teamID) != B_OK) break; - start_team_debugger(teamID, &fSettingsManager, this); + TargetHostInterface* interface; + if (message->FindPointer("interface", reinterpret_cast( + &interface)) != B_OK) { + break; + } + + TeamDebuggerOptions options; + options.settingsManager = &fSettingsManager; + options.team = teamID; + status_t error = interface->StartTeamDebugger(options); + if (error != B_OK) { + // TODO: notify user. + } break; } case MSG_START_NEW_TEAM: { + TargetHostInterface* interface; + if (message->FindPointer("interface", reinterpret_cast( + &interface)) != B_OK) { + break; + } + const char* teamPath = NULL; const char* args = NULL; message->FindString("path", &teamPath); message->FindString("arguments", &args); - status_t result = _StartNewTeam(teamPath, args); + status_t result = _StartNewTeam(interface, teamPath, args); BMessage reply; reply.AddInt32("status", result); message->SendReply(&reply); break; } - case MSG_TEAM_RESTART_REQUESTED: - { - int32 teamID; - if (message->FindInt32("team", &teamID) != B_OK) - break; - TeamDebugger* debugger = _FindTeamDebugger(teamID); - if (debugger == NULL) - break; - - Options options; - options.commandLineArgc = debugger->ArgumentCount(); - options.commandLineArgv = debugger->Arguments(); - - status_t result = _StartOrFindTeam(options); - if (result == B_OK) - debugger->PostMessage(B_QUIT_REQUESTED); - - break; - } - case MSG_TEAM_DEBUGGER_QUIT: - { - int32 threadID; - if (message->FindInt32("thread", &threadID) == B_OK) - wait_for_thread(threadID, NULL); - - --fRunningTeamDebuggers; - Quit(); - break; - } default: BApplication::MessageReceived(message); break; @@ -557,8 +419,10 @@ Debugger::MessageReceived(BMessage* message) void Debugger::ReadyToRun() { - if (fRunningTeamDebuggers == 0) - PostMessage(MSG_SHOW_TEAMS_WINDOW); + TargetHostInterfaceRoster* roster = TargetHostInterfaceRoster::Default(); + AutoLocker lock(roster); + if (roster->CountRunningTeamDebuggers() == 0) + PostMessage(MSG_SHOW_TEAMS_WINDOW); } @@ -571,51 +435,13 @@ Debugger::ArgvReceived(int32 argc, char** argv) return; } - _StartOrFindTeam(options); - -} - - -void -Debugger::TeamDebuggerStarted(TeamDebugger* debugger) -{ - printf("debugger for team %" B_PRId32 " started...\n", debugger->TeamID()); + TargetHostInterface* hostInterface + = TargetHostInterfaceRoster::Default()->ActiveInterfaceAt(0); - // Note: see TeamDebuggerQuit() note about locking - AutoLocker locker(this); - fTeamDebuggers.AddItem(debugger); - fRunningTeamDebuggers++; - locker.Unlock(); -} - - -void -Debugger::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. - - printf("debugger for team %" B_PRId32 " quit.\n", debugger->TeamID()); - - 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); - } -} - - -void -Debugger::TeamDebuggerRestartRequested(TeamDebugger* debugger) -{ - BMessage message(MSG_TEAM_RESTART_REQUESTED); - message.AddInt32("team", debugger->TeamID()); - PostMessage(&message); + TeamDebuggerOptions debuggerOptions; + set_debugger_options_from_options(debuggerOptions, options); + debuggerOptions.settingsManager = &fSettingsManager; + hostInterface->StartTeamDebugger(debuggerOptions); } @@ -639,27 +465,17 @@ Debugger::QuitRequested() void Debugger::Quit() { + TargetHostInterfaceRoster* roster = TargetHostInterfaceRoster::Default(); + AutoLocker lock(roster); // don't quit before all team debuggers have been quit - if (fRunningTeamDebuggers <= 0 && fTeamsWindow == NULL) + if (roster->CountRunningTeamDebuggers() == 0 && fTeamsWindow == NULL) BApplication::Quit(); } -TeamDebugger* -Debugger::_FindTeamDebugger(team_id teamID) const -{ - for (int32 i = 0; TeamDebugger* debugger = fTeamDebuggers.ItemAt(i); - i++) { - if (debugger->TeamID() == teamID) - return debugger; - } - - return NULL; -} - - status_t -Debugger::_StartNewTeam(const char* path, const char* args) +Debugger::_StartNewTeam(TargetHostInterface* interface, const char* path, + const char* args) { if (path == NULL) return B_BAD_VALUE; @@ -672,7 +488,8 @@ Debugger::_StartNewTeam(const char* path, const char* args) ArgumentVector argVector; argVector.Parse(data.String()); - Options options; + TeamDebuggerOptions options; + options.settingsManager = &fSettingsManager; options.commandLineArgc = argVector.ArgumentCount(); if (options.commandLineArgc <= 0) return B_BAD_VALUE; @@ -682,31 +499,11 @@ Debugger::_StartNewTeam(const char* path, const char* args) options.commandLineArgv = argv; MemoryDeleter deleter(argv); - return _StartOrFindTeam(options); -} - - -status_t -Debugger::_StartOrFindTeam(Options& options) -{ - DebuggedProgramInfo programInfo; - if (!get_debugged_program(options, programInfo)) - return B_BAD_VALUE; - - TeamDebugger* debugger = _FindTeamDebugger(programInfo.team); - if (debugger != NULL) { - printf("There's already a debugger for team: %" B_PRId32 "\n", - programInfo.team); - debugger->Activate(); - return B_OK; - } - - status_t result; - start_team_debugger(programInfo.team, &fSettingsManager, this, - programInfo.thread, programInfo.commandLineArgc, - programInfo.commandLineArgv, programInfo.stopInMain, NULL, &result); + status_t error = interface->StartTeamDebugger(options); + if (error == B_OK) + deleter.Detach(); - return result; + return error; } @@ -756,18 +553,20 @@ CliDebugger::Run(const Options& options) } BReference userInterfaceReference(userInterface, true); - // get/run the program to be debugged and start the team debugger - DebuggedProgramInfo programInfo; - if (!get_debugged_program(options, programInfo)) - return false; + // TODO: once we support specifying a remote interface via command line + // args, this needs to be adjusted. For now, always assume actions + // are being taken via the local interface. + TargetHostInterface* hostInterface + = TargetHostInterfaceRoster::Default()->ActiveInterfaceAt(0); - TeamDebugger* teamDebugger = start_team_debugger(programInfo.team, - &settingsManager, this, programInfo.thread, - programInfo.commandLineArgc, programInfo.commandLineArgv, - programInfo.stopInMain, userInterface); - if (teamDebugger == NULL) + TeamDebuggerOptions debuggerOptions; + set_debugger_options_from_options(debuggerOptions, options); + debuggerOptions.userInterface = userInterface; + error = hostInterface->StartTeamDebugger(debuggerOptions); + if (error != B_OK) return false; + TeamDebugger* teamDebugger = hostInterface->TeamDebuggerAt(0); thread_id teamDebuggerThread = teamDebugger->Thread(); // run the input loop @@ -780,25 +579,6 @@ CliDebugger::Run(const Options& options) } -void -CliDebugger::TeamDebuggerStarted(TeamDebugger* debugger) -{ -} - - -void -CliDebugger::TeamDebuggerRestartRequested(TeamDebugger* debugger) -{ - // TODO: implement -} - - -void -CliDebugger::TeamDebuggerQuit(TeamDebugger* debugger) -{ -} - - // #pragma mark - ReportDebugger @@ -840,18 +620,17 @@ ReportDebugger::Run(const Options& options) } BReference userInterfaceReference(userInterface, true); - // get/run the program to be debugged and start the team debugger - DebuggedProgramInfo programInfo; - if (!get_debugged_program(options, programInfo)) - return false; + TargetHostInterface* hostInterface + = TargetHostInterfaceRoster::Default()->ActiveInterfaceAt(0); - TeamDebugger* teamDebugger = start_team_debugger(programInfo.team, - &settingsManager, this, programInfo.thread, - programInfo.commandLineArgc, programInfo.commandLineArgv, - programInfo.stopInMain, userInterface); - if (teamDebugger == NULL) + TeamDebuggerOptions debuggerOptions; + set_debugger_options_from_options(debuggerOptions, options); + debuggerOptions.userInterface = userInterface; + error = hostInterface->StartTeamDebugger(debuggerOptions); + if (error != B_OK) return false; + TeamDebugger* teamDebugger = hostInterface->TeamDebuggerAt(0); thread_id teamDebuggerThread = teamDebugger->Thread(); // run the input loop @@ -864,24 +643,6 @@ ReportDebugger::Run(const Options& options) } -void -ReportDebugger::TeamDebuggerStarted(TeamDebugger* debugger) -{ -} - - -void -ReportDebugger::TeamDebuggerRestartRequested(TeamDebugger* debugger) -{ -} - - -void -ReportDebugger::TeamDebuggerQuit(TeamDebugger* debugger) -{ -} - - // #pragma mark - diff --git a/src/apps/debugger/controllers/TeamDebugger.h b/src/apps/debugger/controllers/TeamDebugger.h index 7cce854a1e..f030618c43 100644 --- a/src/apps/debugger/controllers/TeamDebugger.h +++ b/src/apps/debugger/controllers/TeamDebugger.h @@ -55,6 +55,8 @@ public: { return fCommandLineArgc; } const char** Arguments() const { return fCommandLineArgv; } + SettingsManager* GetSettingsManager() const + { return fSettingsManager; } virtual void MessageReceived(BMessage* message); diff --git a/src/apps/debugger/target_host_interface/TargetHostInterface.cpp b/src/apps/debugger/target_host_interface/TargetHostInterface.cpp index c213c6a5f4..ac5ba67a5f 100644 --- a/src/apps/debugger/target_host_interface/TargetHostInterface.cpp +++ b/src/apps/debugger/target_host_interface/TargetHostInterface.cpp @@ -5,12 +5,37 @@ #include "TargetHostInterface.h" +#include + +#include + +#include "DebuggerInterface.h" +#include "GraphicalUserInterface.h" +#include "MessageCodes.h" #include "TeamDebugger.h" +// #pragma mark - TeamDebuggerOptions + + +TeamDebuggerOptions::TeamDebuggerOptions() + : + commandLineArgc(0), + commandLineArgv(NULL), + team(-1), + thread(-1), + settingsManager(NULL), + userInterface(NULL) +{ +} + + +// #pragma mark - TargetHostInterface + + TargetHostInterface::TargetHostInterface() : - BReferenceable(), + BLooper(), fTeamDebuggers(20, false) { } @@ -21,10 +46,40 @@ TargetHostInterface::~TargetHostInterface() } -void -TargetHostInterface::SetName(const BString& name) +status_t +TargetHostInterface::StartTeamDebugger(const TeamDebuggerOptions& options) { - fName = name; + // we only want to stop in main for teams we're responsible for + // creating ourselves. + bool stopInMain = options.commandLineArgv != NULL; + team_id team = options.team; + thread_id thread = options.thread; + + AutoLocker interfaceLocker(this); + if (options.commandLineArgc > 0) { + status_t error = CreateTeam(options.commandLineArgc, + options.commandLineArgv, team); + if (error != B_OK) + return error; + thread = team; + } + + if (team < 0 && thread < 0) + return B_BAD_VALUE; + + if (team < 0) { + status_t error = FindTeamByThread(thread, team); + if (error != B_OK) + return error; + } + + TeamDebugger* debugger = FindTeamDebugger(team); + if (debugger != NULL) { + debugger->Activate(); + return B_OK; + } + + return _StartTeamDebugger(team, options, stopInMain); } @@ -69,6 +124,133 @@ TargetHostInterface::RemoveTeamDebugger(TeamDebugger* debugger) } +void +TargetHostInterface::Quit() +{ + if (fTeamDebuggers.CountItems() == 0) + BLooper::Quit(); +} + + +void +TargetHostInterface::MessageReceived(BMessage* message) +{ + switch (message->what) { + case MSG_TEAM_DEBUGGER_QUIT: + { + thread_id thread; + if (message->FindInt32("thread", &thread) == B_OK) + wait_for_thread(thread, NULL); + break; + } + case MSG_TEAM_RESTART_REQUESTED: + { + int32 teamID; + if (message->FindInt32("team", &teamID) != B_OK) + break; + + TeamDebugger* debugger = FindTeamDebugger(teamID); + + TeamDebuggerOptions options; + options.commandLineArgc = debugger->ArgumentCount(); + options.commandLineArgv = debugger->Arguments(); + options.settingsManager = debugger->GetSettingsManager(); + status_t result = StartTeamDebugger(options); + if (result == B_OK) + debugger->PostMessage(B_QUIT_REQUESTED); + break; + } + default: + BLooper::MessageReceived(message); + break; + } +} + + +void +TargetHostInterface::TeamDebuggerStarted(TeamDebugger* debugger) +{ + AutoLocker locker(this); + AddTeamDebugger(debugger); +} + + +void +TargetHostInterface::TeamDebuggerRestartRequested(TeamDebugger* debugger) +{ + BMessage message(MSG_TEAM_RESTART_REQUESTED); + message.AddInt32("team", debugger->TeamID()); + PostMessage(&message); +} + + +void +TargetHostInterface::TeamDebuggerQuit(TeamDebugger* debugger) +{ + AutoLocker interfaceLocker(this); + RemoveTeamDebugger(debugger); + interfaceLocker.Unlock(); + + if (debugger->Thread() >= 0) { + BMessage message(MSG_TEAM_DEBUGGER_QUIT); + message.AddInt32("thread", debugger->Thread()); + PostMessage(&message); + } +} + + +status_t +TargetHostInterface::_StartTeamDebugger(team_id teamID, + const TeamDebuggerOptions& options, bool stopInMain) +{ + BReference userInterfaceReference; + UserInterface* userInterface = options.userInterface; + if (userInterface == NULL) { + userInterface = new(std::nothrow) GraphicalUserInterface; + if (userInterface == NULL) { + fprintf(stderr, "Error: Out of memory!\n"); + return B_NO_MEMORY; + } + + userInterfaceReference.SetTo(userInterface, true); + } + + thread_id threadID = options.thread; + if (options.commandLineArgv != NULL) + threadID = teamID; + + DebuggerInterface* interface = NULL; + TeamDebugger* debugger = NULL; + status_t error = Attach(teamID, options.thread, interface); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to attach to team %" B_PRId32 ": %s!\n", + teamID, strerror(error)); + return error; + } + + BReference debuggerInterfaceReference(interface, + true); + debugger = new(std::nothrow) TeamDebugger(this, userInterface, + options.settingsManager); + if (debugger != NULL) { + error = debugger->Init(interface, threadID, + options.commandLineArgc, options.commandLineArgv, stopInMain); + } + + if (error != B_OK) { + printf("Error: debugger for team %" B_PRId32 " on interface %s failed" + " to init: %s!\n", interface->TeamID(), Name(), strerror(error)); + delete debugger; + debugger = NULL; + } else { + printf("debugger for team %" B_PRId32 " on interface %s created and" + " initialized successfully!\n", interface->TeamID(), Name()); + } + + return error; +} + + /*static*/ int TargetHostInterface::_CompareDebuggers(const TeamDebugger* a, const TeamDebugger* b) diff --git a/src/apps/debugger/target_host_interface/TargetHostInterface.h b/src/apps/debugger/target_host_interface/TargetHostInterface.h index d7d95d8f84..84b3576c9b 100644 --- a/src/apps/debugger/target_host_interface/TargetHostInterface.h +++ b/src/apps/debugger/target_host_interface/TargetHostInterface.h @@ -6,26 +6,28 @@ #define TARGET_HOST_INTERFACE_H #include -#include +#include #include -#include + +#include "TeamDebugger.h" class DebuggerInterface; class Settings; +class SettingsManager; class TargetHost; class TeamDebugger; +struct TeamDebuggerOptions; +class UserInterface; -class TargetHostInterface : public BReferenceable { +class TargetHostInterface : public BLooper, private TeamDebugger::Listener { public: TargetHostInterface(); virtual ~TargetHostInterface(); - const BString& Name() const { return fName; } - void SetName(const BString& name); - + status_t StartTeamDebugger(const TeamDebuggerOptions& options); int32 CountTeamDebuggers() const; TeamDebugger* TeamDebuggerAt(int32 index) const; @@ -36,18 +38,35 @@ public: virtual status_t Init(Settings* settings) = 0; virtual void Close() = 0; + virtual bool IsLocal() const = 0; virtual bool Connected() const = 0; virtual TargetHost* GetTargetHost() = 0; virtual status_t Attach(team_id id, thread_id threadID, - DebuggerInterface*& _interface) = 0; + DebuggerInterface*& _interface) const = 0; virtual status_t CreateTeam(int commandLineArgc, const char* const* arguments, - DebuggerInterface*& _interface) = 0; + team_id& _teamID) const = 0; + virtual status_t FindTeamByThread(thread_id thread, + team_id& _teamID) const = 0; + + // BLooper + virtual void Quit(); + virtual void MessageReceived(BMessage* message); + +private: + // TeamDebugger::Listener + virtual void TeamDebuggerStarted(TeamDebugger* debugger); + virtual void TeamDebuggerRestartRequested( + TeamDebugger* debugger); + virtual void TeamDebuggerQuit(TeamDebugger* debugger); private: + status_t _StartTeamDebugger(team_id teamID, + const TeamDebuggerOptions& options, + bool stopInMain); static int _CompareDebuggers(const TeamDebugger* a, const TeamDebugger* b); static int _FindDebuggerByKey(const team_id* team, @@ -56,9 +75,19 @@ private: typedef BObjectList TeamDebuggerList; private: - BString fName; TeamDebuggerList fTeamDebuggers; }; +struct TeamDebuggerOptions { + TeamDebuggerOptions(); + int commandLineArgc; + const char* const* commandLineArgv; + team_id team; + thread_id thread; + SettingsManager* settingsManager; + UserInterface* userInterface; +}; + + #endif // TARGET_HOST_INTERFACE_H diff --git a/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.cpp b/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.cpp index de8b644a2b..5305f7f866 100644 --- a/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.cpp +++ b/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.cpp @@ -130,12 +130,13 @@ TargetHostInterfaceRoster::CreateInterface(TargetHostInterfaceInfo* info, if (error != B_OK) return error; - BReference interfaceReference(interface, true); - if (!fActiveInterfaces.AddItem(interface)) + error = interface->Run(); + if (error < B_OK || !fActiveInterfaces.AddItem(interface)) { + delete interface; return B_NO_MEMORY; + } _interface = interface; - interfaceReference.Detach(); return B_OK; } @@ -153,3 +154,15 @@ TargetHostInterfaceRoster::ActiveInterfaceAt(int32 index) const return fActiveInterfaces.ItemAt(index); } + +int32 +TargetHostInterfaceRoster::CountRunningTeamDebuggers() const +{ + int32 total = 0; + for (int32 i = 0; TargetHostInterface* interface = ActiveInterfaceAt(i); + i++) { + total += interface->CountTeamDebuggers(); + } + + return total; +} diff --git a/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.h b/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.h index 6f3f12bbfc..d09ff9b242 100644 --- a/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.h +++ b/src/apps/debugger/target_host_interface/TargetHostInterfaceRoster.h @@ -42,6 +42,8 @@ public: int32 CountActiveInterfaces() const; TargetHostInterface* ActiveInterfaceAt(int32 index) const; + int32 CountRunningTeamDebuggers() const; + private: typedef BObjectList InfoList; typedef BObjectList InterfaceList; diff --git a/src/apps/debugger/target_host_interface/local/LocalTargetHostInterface.cpp b/src/apps/debugger/target_host_interface/local/LocalTargetHostInterface.cpp index e9a5a474b7..23cfd400bb 100644 --- a/src/apps/debugger/target_host_interface/local/LocalTargetHostInterface.cpp +++ b/src/apps/debugger/target_host_interface/local/LocalTargetHostInterface.cpp @@ -113,6 +113,13 @@ LocalTargetHostInterface::Close() bool +LocalTargetHostInterface::IsLocal() const +{ + return true; +} + + +bool LocalTargetHostInterface::Connected() const { return true; @@ -128,7 +135,7 @@ LocalTargetHostInterface::GetTargetHost() status_t LocalTargetHostInterface::Attach(team_id teamID, thread_id threadID, - DebuggerInterface*& _interface) + DebuggerInterface*& _interface) const { if (teamID < 0 && threadID < 0) return B_BAD_VALUE; @@ -161,13 +168,29 @@ LocalTargetHostInterface::Attach(team_id teamID, thread_id threadID, status_t LocalTargetHostInterface::CreateTeam(int commandLineArgc, - const char* const* arguments, DebuggerInterface*& _interface) + const char* const* arguments, team_id& _teamID) const { thread_id thread = load_program(arguments, commandLineArgc, false); if (thread < 0) return thread; - return Attach(-1, thread, _interface); + // main thread ID == team ID. + _teamID = thread; + return B_OK; +} + + +status_t +LocalTargetHostInterface::FindTeamByThread(thread_id thread, + team_id& _teamID) const +{ + thread_info info; + status_t error = get_thread_info(thread, &info); + if (error != B_OK) + return error; + + _teamID = info.team; + return B_OK; } diff --git a/src/apps/debugger/target_host_interface/local/LocalTargetHostInterface.h b/src/apps/debugger/target_host_interface/local/LocalTargetHostInterface.h index 00f02eedf0..c9f6e7021d 100644 --- a/src/apps/debugger/target_host_interface/local/LocalTargetHostInterface.h +++ b/src/apps/debugger/target_host_interface/local/LocalTargetHostInterface.h @@ -16,16 +16,20 @@ public: virtual status_t Init(Settings* settings); virtual void Close(); + virtual bool IsLocal() const; virtual bool Connected() const; virtual TargetHost* GetTargetHost(); virtual status_t Attach(team_id id, thread_id threadID, - DebuggerInterface*& _interface); + DebuggerInterface*& _interface) const; virtual status_t CreateTeam(int commandLineArgc, const char* const* arguments, - DebuggerInterface*& _interface); + team_id& _teamID) const; + virtual status_t FindTeamByThread(thread_id thread, + team_id& _teamID) const; + private: static status_t _PortLoop(void* arg); diff --git a/src/apps/debugger/target_host_interface/local/LocalTargetHostInterfaceInfo.cpp b/src/apps/debugger/target_host_interface/local/LocalTargetHostInterfaceInfo.cpp index 5ac0f128d3..8940496ff8 100644 --- a/src/apps/debugger/target_host_interface/local/LocalTargetHostInterfaceInfo.cpp +++ b/src/apps/debugger/target_host_interface/local/LocalTargetHostInterfaceInfo.cpp @@ -59,14 +59,13 @@ LocalTargetHostInterfaceInfo::CreateInterface(Settings* settings, if (interface == NULL) return B_NO_MEMORY; - BReference interfaceReference(interface, true); status_t error = interface->Init(settings); - if (error != B_OK) + if (error != B_OK) { + delete interface; return error; + } _interface = interface; - interfaceReference.Detach(); - return B_OK; } diff --git a/src/apps/debugger/user_interface/gui/teams_window/TeamsListView.cpp b/src/apps/debugger/user_interface/gui/teams_window/TeamsListView.cpp index daacb44a3b..029b1ead1b 100644 --- a/src/apps/debugger/user_interface/gui/teams_window/TeamsListView.cpp +++ b/src/apps/debugger/user_interface/gui/teams_window/TeamsListView.cpp @@ -279,7 +279,6 @@ TeamsListView::TeamsListView(const char* name, team_id currentTeam, fCurrentTeam(currentTeam), fInterface(interface) { - fInterface->AcquireReference(); AddColumn(new TeamsColumn("Name", 400, 100, 600, B_TRUNCATE_BEGINNING), kNameColumn); AddColumn(new TeamsColumn("ID", 80, 40, 100, @@ -290,7 +289,6 @@ TeamsListView::TeamsListView(const char* name, team_id currentTeam, TeamsListView::~TeamsListView() { - fInterface->ReleaseReference(); } diff --git a/src/apps/debugger/user_interface/gui/teams_window/TeamsWindow.cpp b/src/apps/debugger/user_interface/gui/teams_window/TeamsWindow.cpp index 53d599dae3..aaa9ae45ae 100644 --- a/src/apps/debugger/user_interface/gui/teams_window/TeamsWindow.cpp +++ b/src/apps/debugger/user_interface/gui/teams_window/TeamsWindow.cpp @@ -24,7 +24,8 @@ #include "MessageCodes.h" #include "SettingsManager.h" -#include "LocalTargetHostInterface.h" +#include "TargetHostInterface.h" +#include "TargetHostInterfaceRoster.h" #include "TeamsListView.h" @@ -51,8 +52,6 @@ TeamsWindow::TeamsWindow(SettingsManager* settingsManager) TeamsWindow::~TeamsWindow() { - if (fTargetHostInterface != NULL) - fTargetHostInterface->ReleaseReference(); } @@ -100,6 +99,7 @@ TeamsWindow::MessageReceived(BMessage* message) if (row != NULL) { BMessage message(MSG_DEBUG_THIS_TEAM); message.AddInt32("team", row->TeamID()); + message.AddPointer("interface", fTargetHostInterface); be_app_messenger.SendMessage(&message); } break; @@ -120,6 +120,14 @@ TeamsWindow::MessageReceived(BMessage* message) break; } + case MSG_SHOW_START_TEAM_WINDOW: + { + BMessage startMessage(*message); + startMessage.AddPointer("interface", fTargetHostInterface); + be_app_messenger.SendMessage(&startMessage); + break; + } + default: BWindow::MessageReceived(message); break; @@ -146,10 +154,8 @@ TeamsWindow::_Init() BMessage settings; _LoadSettings(settings); - fTargetHostInterface = new LocalTargetHostInterface(); - - if (fTargetHostInterface->Init(NULL) != B_OK) - throw std::bad_alloc(); + fTargetHostInterface = TargetHostInterfaceRoster::Default() + ->ActiveInterfaceAt(0); BRect frame; if (settings.FindRect("teams window frame", &frame) == B_OK) { @@ -175,7 +181,7 @@ TeamsWindow::_Init() MSG_TEAM_SELECTION_CHANGED)); fAttachTeamButton->SetEnabled(false); - fCreateTeamButton->SetTarget(be_app); + fCreateTeamButton->SetTarget(this); } diff --git a/src/apps/debugger/user_interface/gui/utility_windows/StartTeamWindow.cpp b/src/apps/debugger/user_interface/gui/utility_windows/StartTeamWindow.cpp index 43af440314..6f1b684ee9 100644 --- a/src/apps/debugger/user_interface/gui/utility_windows/StartTeamWindow.cpp +++ b/src/apps/debugger/user_interface/gui/utility_windows/StartTeamWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013, Rene Gollent, rene@gollent.com. + * Copyright 2013-2016, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #include "StartTeamWindow.h" @@ -24,7 +24,7 @@ enum { }; -StartTeamWindow::StartTeamWindow() +StartTeamWindow::StartTeamWindow(TargetHostInterface* hostInterface) : BWindow(BRect(), "Start new team", B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), @@ -34,7 +34,8 @@ StartTeamWindow::StartTeamWindow() fBrowseTeamButton(NULL), fBrowseTeamPanel(NULL), fStartButton(NULL), - fCancelButton(NULL) + fCancelButton(NULL), + fTargetHostInterface(hostInterface) { } @@ -46,9 +47,9 @@ StartTeamWindow::~StartTeamWindow() StartTeamWindow* -StartTeamWindow::Create() +StartTeamWindow::Create(TargetHostInterface* hostInterface) { - StartTeamWindow* self = new StartTeamWindow; + StartTeamWindow* self = new StartTeamWindow(hostInterface); try { self->_Init(); @@ -141,6 +142,7 @@ StartTeamWindow::MessageReceived(BMessage* message) appMessage.AddString("path", fTeamTextControl->TextView()->Text()); appMessage.AddString("arguments", fArgumentsTextControl->TextView() ->Text()); + appMessage.AddPointer("interface", fTargetHostInterface); BMessage reply; be_app_messenger.SendMessage(&appMessage, &reply); status_t error = reply.FindInt32("status"); diff --git a/src/apps/debugger/user_interface/gui/utility_windows/StartTeamWindow.h b/src/apps/debugger/user_interface/gui/utility_windows/StartTeamWindow.h index c81059e7b8..1f08f8e868 100644 --- a/src/apps/debugger/user_interface/gui/utility_windows/StartTeamWindow.h +++ b/src/apps/debugger/user_interface/gui/utility_windows/StartTeamWindow.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, Rene Gollent, rene@gollent.com. + * Copyright 2013-2016, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #ifndef START_TEAM_WINDOW_H @@ -13,16 +13,18 @@ class BButton; class BFilePanel; class BStringView; class BTextControl; +class TargetHostInterface; class StartTeamWindow : public BWindow { public: - StartTeamWindow(); + StartTeamWindow( + TargetHostInterface* hostInterface); ~StartTeamWindow(); - static StartTeamWindow* Create(); + static StartTeamWindow* Create(TargetHostInterface* hostInterface); // throws @@ -42,6 +44,7 @@ private: BFilePanel* fBrowseTeamPanel; BButton* fStartButton; BButton* fCancelButton; + TargetHostInterface* fTargetHostInterface; }; #endif // START_TEAM_WINDOW_H -- 2.11.4.GIT