Debugger CLI: Move more stuff to and extend CliContext
* Move the libedit interface there and provide nicer to use methods. * Also start adding utility methods for the input loop. It is going to manage all interactions of the input loop with outside events. * Fix the "quit" command. The user is now prompted what to do with the debugged team and the input loop thread avoids reentering the input loop.
This commit is contained in:
parent
eba38eb503
commit
8fe9f8b2d0
@ -6,27 +6,160 @@
|
||||
|
||||
#include "CliContext.h"
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "UserInterface.h"
|
||||
|
||||
|
||||
// NOTE: This is a simple work-around for EditLine not having any kind of user
|
||||
// data field. Hence in _GetPrompt() we don't have access to the context object.
|
||||
// ATM only one CLI is possible in Debugger, so a static variable works well
|
||||
// enough. Should that ever change, we would need a thread-safe
|
||||
// EditLine* -> CliContext* map.
|
||||
static CliContext* sCurrentContext;
|
||||
|
||||
|
||||
CliContext::CliContext()
|
||||
:
|
||||
fLock("CliContext"),
|
||||
fTeam(NULL),
|
||||
fListener(NULL)
|
||||
fListener(NULL),
|
||||
fEditLine(NULL),
|
||||
fHistory(NULL),
|
||||
fPrompt(NULL),
|
||||
fBlockingSemaphore(-1),
|
||||
fInputLoopWaiting(false),
|
||||
fTerminating(false)
|
||||
{
|
||||
sCurrentContext = this;
|
||||
}
|
||||
|
||||
CliContext::~CliContext()
|
||||
{
|
||||
Cleanup();
|
||||
sCurrentContext = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
status_t
|
||||
CliContext::Init(Team* team, UserInterfaceListener* listener)
|
||||
{
|
||||
fTeam = team;
|
||||
fListener = listener;
|
||||
|
||||
status_t error = fLock.InitCheck();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
fBlockingSemaphore = create_sem(0, "CliContext block");
|
||||
if (fBlockingSemaphore < 0)
|
||||
return fBlockingSemaphore;
|
||||
|
||||
fEditLine = el_init("Debugger", stdin, stdout, stderr);
|
||||
if (fEditLine == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
fHistory = history_init();
|
||||
if (fHistory == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
HistEvent historyEvent;
|
||||
history(fHistory, &historyEvent, H_SETSIZE, 100);
|
||||
|
||||
el_set(fEditLine, EL_HIST, &history, fHistory);
|
||||
el_set(fEditLine, EL_EDITOR, "emacs");
|
||||
el_set(fEditLine, EL_PROMPT, &_GetPrompt);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::QuitSession()
|
||||
CliContext::Cleanup()
|
||||
{
|
||||
fListener->UserInterfaceQuitRequested();
|
||||
Terminating();
|
||||
|
||||
if (fEditLine != NULL) {
|
||||
el_end(fEditLine);
|
||||
fEditLine = NULL;
|
||||
}
|
||||
|
||||
if (fHistory != NULL) {
|
||||
history_end(fHistory);
|
||||
fHistory = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::Terminating()
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
fTerminating = true;
|
||||
|
||||
if (fBlockingSemaphore >= 0) {
|
||||
delete_sem(fBlockingSemaphore);
|
||||
fBlockingSemaphore = -1;
|
||||
}
|
||||
|
||||
fInputLoopWaiting = false;
|
||||
|
||||
// TODO: Signal the input loop, should it be in PromptUser()!
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
CliContext::PromptUser(const char* prompt)
|
||||
{
|
||||
fPrompt = prompt;
|
||||
|
||||
int count;
|
||||
const char* line = el_gets(fEditLine, &count);
|
||||
|
||||
fPrompt = NULL;
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::AddLineToInputHistory(const char* line)
|
||||
{
|
||||
HistEvent historyEvent;
|
||||
history(fHistory, &historyEvent, H_ENTER, line);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::QuitSession(bool killTeam)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
sem_id blockingSemaphore = fBlockingSemaphore;
|
||||
fInputLoopWaiting = true;
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
fListener->UserInterfaceQuitRequested(
|
||||
killTeam
|
||||
? UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM
|
||||
: UserInterfaceListener::QUIT_OPTION_ASK_RESUME_TEAM);
|
||||
|
||||
while (acquire_sem(blockingSemaphore) == B_INTERRUPTED) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::WaitForThreadOrUser()
|
||||
{
|
||||
// TODO:...
|
||||
}
|
||||
|
||||
|
||||
/*static*/ const char*
|
||||
CliContext::_GetPrompt(EditLine* editLine)
|
||||
{
|
||||
return sCurrentContext != NULL ? sCurrentContext->fPrompt : NULL;
|
||||
}
|
||||
|
@ -6,6 +6,13 @@
|
||||
#define CLI_CONTEXT_H
|
||||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
// Needed in histedit.h.
|
||||
#include <histedit.h>
|
||||
|
||||
#include <Locker.h>
|
||||
|
||||
|
||||
class Team;
|
||||
class UserInterfaceListener;
|
||||
|
||||
@ -13,18 +20,38 @@ class UserInterfaceListener;
|
||||
class CliContext {
|
||||
public:
|
||||
CliContext();
|
||||
~CliContext();
|
||||
|
||||
void Init(Team* team,
|
||||
status_t Init(Team* team,
|
||||
UserInterfaceListener* listener);
|
||||
void Cleanup();
|
||||
|
||||
void Terminating();
|
||||
|
||||
// service methods for the input loop thread follow
|
||||
|
||||
Team* GetTeam() const { return fTeam; }
|
||||
|
||||
void QuitSession();
|
||||
const char* PromptUser(const char* prompt);
|
||||
void AddLineToInputHistory(const char* line);
|
||||
|
||||
void QuitSession(bool killTeam);
|
||||
|
||||
void WaitForThreadOrUser();
|
||||
|
||||
private:
|
||||
static const char* _GetPrompt(EditLine* editLine);
|
||||
|
||||
private:
|
||||
BLocker fLock;
|
||||
Team* fTeam;
|
||||
UserInterfaceListener* fListener;
|
||||
EditLine* fEditLine;
|
||||
History* fHistory;
|
||||
const char* fPrompt;
|
||||
sem_id fBlockingSemaphore;
|
||||
bool fInputLoopWaiting;
|
||||
volatile bool fTerminating;
|
||||
};
|
||||
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "CliQuitCommand.h"
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "CliContext.h"
|
||||
|
||||
|
||||
@ -21,5 +23,27 @@ CliQuitCommand::CliQuitCommand()
|
||||
void
|
||||
CliQuitCommand::Execute(int argc, const char* const* argv, CliContext& context)
|
||||
{
|
||||
context.QuitSession();
|
||||
// Ask the user what to do with the debugged team.
|
||||
printf("Kill or resume the debugged team?\n");
|
||||
for (;;) {
|
||||
const char* line = context.PromptUser("(k)ill, (r)esume, (c)ancel? ");
|
||||
if (line == NULL)
|
||||
return;
|
||||
|
||||
BString trimmedLine(line);
|
||||
trimmedLine.Trim();
|
||||
|
||||
if (trimmedLine == "k") {
|
||||
context.QuitSession(true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (trimmedLine == "r") {
|
||||
context.QuitSession(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (trimmedLine == "d")
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -20,11 +20,7 @@
|
||||
#include "CliThreadsCommand.h"
|
||||
|
||||
|
||||
static const char*
|
||||
get_prompt(EditLine* editLine)
|
||||
{
|
||||
return "debugger> ";
|
||||
}
|
||||
static const char* kDebuggerPrompt = "debugger> ";
|
||||
|
||||
|
||||
// #pragma mark - CommandEntry
|
||||
@ -83,8 +79,6 @@ private:
|
||||
CommandLineUserInterface::CommandLineUserInterface()
|
||||
:
|
||||
fCommands(20, true),
|
||||
fEditLine(NULL),
|
||||
fHistory(NULL),
|
||||
fShowSemaphore(-1),
|
||||
fShown(false),
|
||||
fTerminating(false)
|
||||
@ -96,12 +90,6 @@ CommandLineUserInterface::~CommandLineUserInterface()
|
||||
{
|
||||
if (fShowSemaphore >= 0)
|
||||
delete_sem(fShowSemaphore);
|
||||
|
||||
if (fEditLine != NULL)
|
||||
el_end(fEditLine);
|
||||
|
||||
if (fHistory != NULL)
|
||||
history_end(fHistory);
|
||||
}
|
||||
|
||||
|
||||
@ -115,9 +103,11 @@ CommandLineUserInterface::ID() const
|
||||
status_t
|
||||
CommandLineUserInterface::Init(Team* team, UserInterfaceListener* listener)
|
||||
{
|
||||
fContext.Init(team, listener);
|
||||
status_t error = fContext.Init(team, listener);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
status_t error = _RegisterCommands();
|
||||
error = _RegisterCommands();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
@ -125,21 +115,6 @@ CommandLineUserInterface::Init(Team* team, UserInterfaceListener* listener)
|
||||
if (fShowSemaphore < 0)
|
||||
return fShowSemaphore;
|
||||
|
||||
fEditLine = el_init("Debugger", stdin, stdout, stderr);
|
||||
if (fEditLine == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
fHistory = history_init();
|
||||
if (fHistory == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
HistEvent historyEvent;
|
||||
history(fHistory, &historyEvent, H_SETSIZE, 100);
|
||||
|
||||
el_set(fEditLine, EL_HIST, &history, fHistory);
|
||||
el_set(fEditLine, EL_EDITOR, "emacs");
|
||||
el_set(fEditLine, EL_PROMPT, &get_prompt);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -158,7 +133,7 @@ CommandLineUserInterface::Terminate()
|
||||
fTerminating = true;
|
||||
|
||||
if (fShown) {
|
||||
// TODO: Signal the thread so it wakes up!
|
||||
fContext.Terminating();
|
||||
|
||||
// Wait for input loop to finish.
|
||||
while (acquire_sem(fShowSemaphore) == B_INTERRUPTED) {
|
||||
@ -169,15 +144,7 @@ CommandLineUserInterface::Terminate()
|
||||
fShowSemaphore = -1;
|
||||
}
|
||||
|
||||
if (fEditLine != NULL) {
|
||||
el_end(fEditLine);
|
||||
fEditLine = NULL;
|
||||
}
|
||||
|
||||
if (fHistory != NULL) {
|
||||
history_end(fHistory);
|
||||
fHistory = NULL;
|
||||
}
|
||||
fContext.Cleanup();
|
||||
}
|
||||
|
||||
|
||||
@ -241,9 +208,11 @@ status_t
|
||||
CommandLineUserInterface::_InputLoop()
|
||||
{
|
||||
while (!fTerminating) {
|
||||
// Wait for a thread or Ctrl-C.
|
||||
fContext.WaitForThreadOrUser();
|
||||
|
||||
// read a command line
|
||||
int count;
|
||||
const char* line = el_gets(fEditLine, &count);
|
||||
const char* line = fContext.PromptUser(kDebuggerPrompt);
|
||||
if (line == NULL)
|
||||
break;
|
||||
|
||||
@ -269,8 +238,7 @@ CommandLineUserInterface::_InputLoop()
|
||||
continue;
|
||||
|
||||
// add line to history
|
||||
HistEvent historyEvent;
|
||||
history(fHistory, &historyEvent, H_ENTER, line);
|
||||
fContext.AddLineToInputHistory(line);
|
||||
|
||||
// execute command
|
||||
_ExecuteCommand(args.ArgumentCount(), args.Arguments());
|
||||
|
@ -7,10 +7,6 @@
|
||||
#define COMMAND_LINE_USER_INTERFACE_H
|
||||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
// Needed in histedit.h.
|
||||
#include <histedit.h>
|
||||
|
||||
#include <ObjectList.h>
|
||||
#include <String.h>
|
||||
|
||||
@ -73,11 +69,9 @@ private:
|
||||
private:
|
||||
CliContext fContext;
|
||||
CommandList fCommands;
|
||||
EditLine* fEditLine;
|
||||
History* fHistory;
|
||||
sem_id fShowSemaphore;
|
||||
bool fShown;
|
||||
bool fTerminating;
|
||||
volatile bool fTerminating;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user