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:
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user