Various improvements to CliContext.

- CliContext now tracks the current stack trace and frame if applicable.

- CliContext now carries a value node manager. This allows it to track
  the variables in the currently active frame.
This commit is contained in:
Rene Gollent
2012-12-16 22:03:35 -05:00
parent 74f911be74
commit 1325ad5fe8
2 changed files with 95 additions and 9 deletions
@@ -1,4 +1,5 @@
/*
* Copyright 2012, Rene Gollent, [email protected].
* Copyright 2012, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
@@ -9,8 +10,9 @@
#include <AutoDeleter.h>
#include <AutoLocker.h>
#include "StackTrace.h"
#include "UserInterface.h"
#include "ValueNodeManager.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.
@@ -55,6 +57,7 @@ CliContext::CliContext()
fLock("CliContext"),
fTeam(NULL),
fListener(NULL),
fNodeManager(NULL),
fEditLine(NULL),
fHistory(NULL),
fPrompt(NULL),
@@ -63,7 +66,9 @@ CliContext::CliContext()
fEventsOccurred(0),
fInputLoopWaiting(false),
fTerminating(false),
fCurrentThread(NULL)
fCurrentThread(NULL),
fCurrentStackTrace(NULL),
fCurrentStackFrameIndex(-1)
{
sCurrentContext = this;
}
@@ -110,6 +115,10 @@ CliContext::Init(Team* team, UserInterfaceListener* listener)
el_set(fEditLine, EL_EDITOR, "emacs");
el_set(fEditLine, EL_PROMPT, &_GetPrompt);
fNodeManager = new(std::nothrow) ValueNodeManager();
if (fNodeManager == NULL)
return B_NO_MEMORY;
return B_OK;
}
@@ -136,6 +145,11 @@ CliContext::Cleanup()
fTeam->RemoveListener(this);
fTeam = NULL;
}
if (fNodeManager != NULL) {
fNodeManager->ReleaseReference();
fNodeManager = NULL;
}
}
@@ -168,8 +182,25 @@ CliContext::SetCurrentThread(Thread* thread)
fCurrentThread = thread;
if (fCurrentThread != NULL)
if (fCurrentStackTrace != NULL) {
fCurrentStackTrace->ReleaseReference();
fCurrentStackTrace = NULL;
fCurrentStackFrameIndex = -1;
fNodeManager->SetStackFrame(NULL, NULL);
}
if (fCurrentThread != NULL) {
fCurrentThread->AcquireReference();
StackTrace* stackTrace = fCurrentThread->GetStackTrace();
// if the thread's stack trace has already been loaded,
// set it, otherwise we'll set it when we process the thread's
// stack trace changed event.
if (stackTrace != NULL) {
fCurrentStackTrace = stackTrace;
fCurrentStackTrace->AcquireReference();
SetCurrentStackFrameIndex(0);
}
}
}
@@ -186,6 +217,24 @@ CliContext::PrintCurrentThread()
}
void
CliContext::SetCurrentStackFrameIndex(int32 index)
{
AutoLocker<BLocker> locker(fLock);
if (fCurrentStackTrace == NULL)
return;
else if (index < 0 || index >= fCurrentStackTrace->CountFrames())
return;
fCurrentStackFrameIndex = index;
StackFrame* frame = fCurrentStackTrace->FrameAt(index);
if (frame != NULL)
fNodeManager->SetStackFrame(fCurrentThread, frame);
}
const char*
CliContext::PromptUser(const char* prompt)
{
@@ -253,7 +302,7 @@ CliContext::WaitForThreadOrUser()
if (stoppedThread != NULL) {
if (fCurrentThread == NULL)
fCurrentThread = stoppedThread;
SetCurrentThread(stoppedThread);
_SignalInputLoop(EVENT_THREAD_STOPPED);
}
@@ -300,6 +349,13 @@ CliContext::ProcessPendingEvents()
printf("[thread stopped: %" B_PRId32 " \"%s\"]\n",
thread->ID(), thread->Name());
break;
case EVENT_THREAD_STACK_TRACE_CHANGED:
if (thread == fCurrentThread) {
fCurrentStackTrace = thread->GetStackTrace();
fCurrentStackTrace->AcquireReference();
SetCurrentStackFrameIndex(0);
}
break;
}
}
}
@@ -335,6 +391,19 @@ CliContext::ThreadStateChanged(const Team::ThreadEvent& threadEvent)
}
void
CliContext::ThreadStackTraceChanged(const Team::ThreadEvent& threadEvent)
{
if (threadEvent.GetThread()->State() != THREAD_STATE_STOPPED)
return;
_QueueEvent(
new(std::nothrow) Event(EVENT_THREAD_STACK_TRACE_CHANGED,
threadEvent.GetThread()));
_SignalInputLoop(EVENT_THREAD_STACK_TRACE_CHANGED);
}
void
CliContext::_QueueEvent(Event* event)
{
@@ -15,18 +15,22 @@
#include "Team.h"
class StackFrame;
class StackTrace;
class Team;
class UserInterfaceListener;
class ValueNodeManager;
class CliContext : private Team::Listener {
public:
enum {
EVENT_QUIT = 0x01,
EVENT_USER_INTERRUPT = 0x02,
EVENT_THREAD_ADDED = 0x04,
EVENT_THREAD_REMOVED = 0x08,
EVENT_THREAD_STOPPED = 0x10,
EVENT_QUIT = 0x01,
EVENT_USER_INTERRUPT = 0x02,
EVENT_THREAD_ADDED = 0x04,
EVENT_THREAD_REMOVED = 0x08,
EVENT_THREAD_STOPPED = 0x10,
EVENT_THREAD_STACK_TRACE_CHANGED = 0x20
};
public:
@@ -46,12 +50,20 @@ public:
Team* GetTeam() const { return fTeam; }
UserInterfaceListener* GetUserInterfaceListener() const
{ return fListener; }
ValueNodeManager* GetValueNodeManager() const
{ return fNodeManager; }
StackTrace* GetStackTrace() const
{ return fCurrentStackTrace; }
Thread* CurrentThread() const { return fCurrentThread; }
thread_id CurrentThreadID() const;
void SetCurrentThread(Thread* thread);
void PrintCurrentThread();
int32 CurrentStackFrameIndex() const
{ return fCurrentStackFrameIndex; }
void SetCurrentStackFrameIndex(int32 index);
const char* PromptUser(const char* prompt);
void AddLineToInputHistory(const char* line);
@@ -72,6 +84,8 @@ private:
virtual void ThreadStateChanged(
const Team::ThreadEvent& event);
virtual void ThreadStackTraceChanged(
const Team::ThreadEvent& event);
private:
void _QueueEvent(Event* event);
@@ -86,6 +100,7 @@ private:
BLocker fLock;
Team* fTeam;
UserInterfaceListener* fListener;
ValueNodeManager* fNodeManager;
EditLine* fEditLine;
History* fHistory;
const char* fPrompt;
@@ -96,6 +111,8 @@ private:
volatile bool fTerminating;
Thread* fCurrentThread;
StackTrace* fCurrentStackTrace;
int32 fCurrentStackFrameIndex;
EventList fPendingEvents;
};