aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Weinhold <ingo_weinhold@gmx.de>2012-07-21 09:18:34 +0200
committerIngo Weinhold <ingo_weinhold@gmx.de>2012-07-21 09:19:18 +0200
commit0a592099a94eb3727053c0e2ca571398dff75701 (patch)
tree836be5c447b2a80e8592f1d3dd8cd21e5c041da3
parent5ba5e31f8a59cb5f3299edd7af256d0fb4db12aa (diff)
Debugger: Rework CLI setup to no longer create a BApplicationhrev44371
The main thread does now serve the CLI input loop.
-rw-r--r--src/apps/debugger/Debugger.cpp259
-rw-r--r--src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp47
-rw-r--r--src/apps/debugger/user_interface/cli/CommandLineUserInterface.h8
3 files changed, 245 insertions, 69 deletions
diff --git a/src/apps/debugger/Debugger.cpp b/src/apps/debugger/Debugger.cpp
index f5617470aa..bac8ac0d13 100644
--- a/src/apps/debugger/Debugger.cpp
+++ b/src/apps/debugger/Debugger.cpp
@@ -88,6 +88,13 @@ struct Options {
};
+struct DebuggedProgramInfo {
+ team_id team;
+ thread_id thread;
+ bool stopInMain;
+};
+
+
static bool
parse_arguments(int argc, const char* const* argv, bool noOutput,
Options& options)
@@ -174,25 +181,104 @@ parse_arguments(int argc, const char* const* argv, bool noOutput,
return true;
}
+static status_t
+global_init()
+{
+ status_t error = TypeHandlerRoster::CreateDefault();
+ if (error != B_OK)
+ return error;
+
+ error = ValueHandlerRoster::CreateDefault();
+ 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 \"%ld\": "
+ "%s\n", thread, strerror(error));
+ return false;
+ }
+
+ team = threadInfo.team;
+ }
+ printf("team: %ld, thread: %ld\n", team, thread);
+
+ _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,
- bool stopInMain = false, bool useCLI = false)
+ bool stopInMain = false, UserInterface* userInterface = NULL)
{
if (teamID < 0)
return NULL;
- UserInterface* userInterface = useCLI
- ? (UserInterface*)new(std::nothrow) CommandLineUserInterface
- : (UserInterface*)new(std::nothrow) GraphicalUserInterface;
-
+ BReference<UserInterface> userInterfaceReference;
if (userInterface == NULL) {
- // TODO: Notify the user!
- fprintf(stderr, "Error: Out of memory!\n");
- return 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<UserInterface> userInterfaceReference(userInterface, true);
status_t error = B_NO_MEMORY;
@@ -213,6 +299,7 @@ start_team_debugger(team_id teamID, SettingsManager* settingsManager,
return debugger;
}
+
// #pragma mark - Debugger application class
@@ -247,6 +334,26 @@ private:
};
+// #pragma mark - CliDebugger
+
+
+class CliDebugger : private TeamDebugger::Listener {
+public:
+ CliDebugger();
+ ~CliDebugger();
+
+ bool Run(const Options& options);
+
+private:
+ // TeamDebugger::Listener
+ virtual void TeamDebuggerStarted(TeamDebugger* debugger);
+ virtual void TeamDebuggerQuit(TeamDebugger* debugger);
+};
+
+
+// #pragma mark - Debugger application class
+
+
Debugger::Debugger()
:
BApplication(kDebuggerSignature),
@@ -266,11 +373,7 @@ Debugger::~Debugger()
status_t
Debugger::Init()
{
- status_t error = TypeHandlerRoster::CreateDefault();
- if (error != B_OK)
- return error;
-
- error = ValueHandlerRoster::CreateDefault();
+ status_t error = global_init();
if (error != B_OK)
return error;
@@ -348,63 +451,22 @@ Debugger::ArgvReceived(int32 argc, char** argv)
return;
}
- 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;
- }
-
- 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)
+ DebuggedProgramInfo programInfo;
+ if (!get_debugged_program(options, programInfo))
return;
- // If we've got
- 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 \"%ld\": "
- "%s\n", thread, strerror(error));
- return;
- }
-
- team = threadInfo.team;
- }
- printf("team: %ld, thread: %ld\n", team, thread);
-
- TeamDebugger* debugger = _FindTeamDebugger(team);
+ TeamDebugger* debugger = _FindTeamDebugger(programInfo.team);
if (debugger != NULL) {
- printf("There's already a debugger for team: %ld\n", team);
+ printf("There's already a debugger for team: %ld\n", programInfo.team);
debugger->Activate();
return;
}
- start_team_debugger(team, &fSettingsManager, this, thread, stopInMain,
- options.useCLI);
+ start_team_debugger(programInfo.team, &fSettingsManager, this,
+ programInfo.thread, programInfo.stopInMain);
}
-// TeamDebugger::Listener
-
-
void
Debugger::TeamDebuggerStarted(TeamDebugger* debugger)
{
@@ -480,6 +542,76 @@ Debugger::_FindTeamDebugger(team_id teamID) const
}
+// #pragma mark - CliDebugger
+
+
+CliDebugger::CliDebugger()
+{
+}
+
+
+CliDebugger::~CliDebugger()
+{
+}
+
+
+bool
+CliDebugger::Run(const Options& options)
+{
+ // initialize global objects and settings manager
+ status_t error = global_init();
+ if (error != B_OK) {
+ fprintf(stderr, "Error: Global initialization failed: %s\n",
+ strerror(error));
+ return false;
+ }
+
+ SettingsManager settingsManager;
+ error = settingsManager.Init();
+ if (error != B_OK) {
+ fprintf(stderr, "Error: Settings manager initialization failed: "
+ "%s\n", strerror(error));
+ return false;
+ }
+
+ // create the command line UI
+ CommandLineUserInterface* userInterface
+ = new(std::nothrow) CommandLineUserInterface;
+ if (userInterface == NULL) {
+ fprintf(stderr, "Error: Out of memory!\n");
+ return false;
+ }
+ 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;
+
+ if (start_team_debugger(programInfo.team, &settingsManager, this,
+ programInfo.thread, programInfo.stopInMain, userInterface)
+ == NULL) {
+ return false;
+ }
+
+ userInterface->Run();
+
+ return true;
+}
+
+
+void
+CliDebugger::TeamDebuggerStarted(TeamDebugger* debugger)
+{
+}
+
+
+void
+CliDebugger::TeamDebuggerQuit(TeamDebugger* debugger)
+{
+}
+
+
// #pragma mark -
@@ -495,6 +627,11 @@ main(int argc, const char* const* argv)
Options options;
parse_arguments(argc, argv, false, options);
+ if (options.useCLI) {
+ CliDebugger debugger;
+ return debugger.Run(options) ? 0 : 1;
+ }
+
Debugger app;
status_t error = app.Init();
if (error != B_OK) {
diff --git a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp
index ab53011fb2..09db85f913 100644
--- a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp
+++ b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp
@@ -96,10 +96,11 @@ private:
CommandLineUserInterface::CommandLineUserInterface()
:
- fThread(-1),
fTeam(NULL),
fListener(NULL),
fCommands(20, true),
+ fShowSemaphore(-1),
+ fShown(false),
fTerminating(false)
{
}
@@ -107,6 +108,8 @@ CommandLineUserInterface::CommandLineUserInterface()
CommandLineUserInterface::~CommandLineUserInterface()
{
+ if (fShowSemaphore >= 0)
+ delete_sem(fShowSemaphore);
}
@@ -127,9 +130,9 @@ CommandLineUserInterface::Init(Team* team, UserInterfaceListener* listener)
if (error != B_OK)
return error;
- fThread = spawn_thread(&_InputLoopEntry, "CLI", B_NORMAL_PRIORITY, this);
- if (fThread < 0)
- return fThread;
+ fShowSemaphore = create_sem(0, "show CLI");
+ if (fShowSemaphore < 0)
+ return fShowSemaphore;
return B_OK;
}
@@ -138,7 +141,8 @@ CommandLineUserInterface::Init(Team* team, UserInterfaceListener* listener)
void
CommandLineUserInterface::Show()
{
- resume_thread(fThread);
+ fShown = true;
+ release_sem(fShowSemaphore);
}
@@ -146,8 +150,18 @@ void
CommandLineUserInterface::Terminate()
{
fTerminating = true;
- // TODO: Signal the thread so it wakes up!
- wait_for_thread(fThread, NULL);
+
+ if (fShown) {
+ // TODO: Signal the thread so it wakes up!
+
+ // Wait for input loop to finish.
+ while (acquire_sem(fShowSemaphore) == B_INTERRUPTED) {
+ }
+ } else {
+ // The main thread will still be blocked in Run(). Unblock it.
+ delete_sem(fShowSemaphore);
+ fShowSemaphore = -1;
+ }
}
@@ -181,6 +195,25 @@ CommandLineUserInterface::SynchronouslyAskUser(const char* title,
}
+void
+CommandLineUserInterface::Run()
+{
+ // Wait for the Show() semaphore to be released.
+ status_t error;
+ do {
+ error = acquire_sem(fShowSemaphore);
+ } while (error == B_INTERRUPTED);
+
+ if (error != B_OK)
+ return;
+
+ _InputLoop();
+
+ // Release the Show() semaphore to signal Terminate().
+ release_sem(fShowSemaphore);
+}
+
+
/*static*/ status_t
CommandLineUserInterface::_InputLoopEntry(void* data)
{
diff --git a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.h b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.h
index b581f36b90..9d0c0714b5 100644
--- a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.h
+++ b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.h
@@ -40,6 +40,11 @@ public:
const char* message, const char* choice1,
const char* choice2, const char* choice3);
+ void Run();
+ // Called by the main thread, when
+ // everything has been set up. Enters the
+ // input loop.
+
private:
struct CommandEntry;
typedef BObjectList<CommandEntry> CommandList;
@@ -63,10 +68,11 @@ private:
void _PrintHelp();
private:
- thread_id fThread;
Team* fTeam;
UserInterfaceListener* fListener;
CommandList fCommands;
+ sem_id fShowSemaphore;
+ bool fShown;
bool fTerminating;
};