hrev44371 adds 1 changeset to branch 'master' old head: 5ba5e31f8a59cb5f3299edd7af256d0fb4db12aa new head: 0a592099a94eb3727053c0e2ca571398dff75701 ---------------------------------------------------------------------------- 0a59209: Debugger: Rework CLI setup to no longer create a BApplication The main thread does now serve the CLI input loop. [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev44371 Commit: 0a592099a94eb3727053c0e2ca571398dff75701 URL: http://cgit.haiku-os.org/haiku/commit/?id=0a59209 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Sat Jul 21 07:18:34 2012 UTC ---------------------------------------------------------------------------- 3 files changed, 245 insertions(+), 69 deletions(-) src/apps/debugger/Debugger.cpp | 259 ++++++++++++---- .../cli/CommandLineUserInterface.cpp | 47 ++- .../user_interface/cli/CommandLineUserInterface.h | 8 +- ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/Debugger.cpp b/src/apps/debugger/Debugger.cpp index f561747..bac8ac0 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 ab53011..09db85f 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 b581f36..9d0c071 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; };