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.
This commit is contained in:
Rene Gollent 2016-04-20 19:23:01 -04:00
parent 52da2024d0
commit a1afac4dca
13 changed files with 408 additions and 384 deletions

View File

@ -20,10 +20,8 @@
#include <AutoLocker.h>
#include <ObjectList.h>
#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;
error = TargetHostInterfaceRoster::CreateDefault();
if (error != B_OK)
return error;
// 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;
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<UserInterface> 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<DebuggerInterface> 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;
TeamDebugger* debugger = new(std::nothrow) TeamDebugger(listener,
userInterface, settingsManager);
if (debugger != NULL) {
error = debugger->Init(debuggerInterface, threadID, commandLineArgc,
commandLineArgv, stopInMain);
}
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;
}
// #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<TeamDebugger> 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<void**>(&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<void**>(
&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<void**>(
&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<TargetHostInterfaceRoster> lock(roster);
if (roster->CountRunningTeamDebuggers() == 0)
PostMessage(MSG_SHOW_TEAMS_WINDOW);
}
@ -571,51 +435,13 @@ Debugger::ArgvReceived(int32 argc, char** argv)
return;
}
_StartOrFindTeam(options);
TargetHostInterface* hostInterface
= TargetHostInterfaceRoster::Default()->ActiveInterfaceAt(0);
}
void
Debugger::TeamDebuggerStarted(TeamDebugger* debugger)
{
printf("debugger for team %" B_PRId32 " started...\n", debugger->TeamID());
// Note: see TeamDebuggerQuit() note about locking
AutoLocker<Debugger> 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<Debugger> 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<TargetHostInterfaceRoster> 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 error = interface->StartTeamDebugger(options);
if (error == B_OK)
deleter.Detach();
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);
return result;
return error;
}
@ -756,18 +553,20 @@ CliDebugger::Run(const Options& options)
}
BReference<UserInterface> 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;
TeamDebugger* teamDebugger = start_team_debugger(programInfo.team,
&settingsManager, this, programInfo.thread,
programInfo.commandLineArgc, programInfo.commandLineArgv,
programInfo.stopInMain, userInterface);
if (teamDebugger == NULL)
// 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);
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<UserInterface> 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;
TeamDebugger* teamDebugger = start_team_debugger(programInfo.team,
&settingsManager, this, programInfo.thread,
programInfo.commandLineArgc, programInfo.commandLineArgv,
programInfo.stopInMain, userInterface);
if (teamDebugger == NULL)
TargetHostInterface* hostInterface
= TargetHostInterfaceRoster::Default()->ActiveInterfaceAt(0);
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 -

View File

@ -55,6 +55,8 @@ public:
{ return fCommandLineArgc; }
const char** Arguments() const
{ return fCommandLineArgv; }
SettingsManager* GetSettingsManager() const
{ return fSettingsManager; }
virtual void MessageReceived(BMessage* message);

View File

@ -5,12 +5,37 @@
#include "TargetHostInterface.h"
#include <stdio.h>
#include <AutoLocker.h>
#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<TargetHostInterface> 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<TargetHostInterface> 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<TargetHostInterface> 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<UserInterface> 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<DebuggerInterface> 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)

View File

@ -6,26 +6,28 @@
#define TARGET_HOST_INTERFACE_H
#include <OS.h>
#include <String.h>
#include <Looper.h>
#include <ObjectList.h>
#include <Referenceable.h>
#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<TeamDebugger> 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

View File

@ -130,12 +130,13 @@ TargetHostInterfaceRoster::CreateInterface(TargetHostInterfaceInfo* info,
if (error != B_OK)
return error;
BReference<TargetHostInterface> 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;
}

View File

@ -42,6 +42,8 @@ public:
int32 CountActiveInterfaces() const;
TargetHostInterface* ActiveInterfaceAt(int32 index) const;
int32 CountRunningTeamDebuggers() const;
private:
typedef BObjectList<TargetHostInterfaceInfo> InfoList;
typedef BObjectList<TargetHostInterface> InterfaceList;

View File

@ -112,6 +112,13 @@ LocalTargetHostInterface::Close()
}
bool
LocalTargetHostInterface::IsLocal() const
{
return true;
}
bool
LocalTargetHostInterface::Connected() const
{
@ -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;
}

View File

@ -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);

View File

@ -59,14 +59,13 @@ LocalTargetHostInterfaceInfo::CreateInterface(Settings* settings,
if (interface == NULL)
return B_NO_MEMORY;
BReference<LocalTargetHostInterface> 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;
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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");

View File

@ -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