Debugger: Make CliContext use BLooper for message passing
This commit replaces the custom implementation of message passing with BLooper. This commit does not fully transition the code to the BLooper paradigm. WaitForEvent still exists, when, ideally, message passing should be used to notify the waiting class that the results are ready. Change-Id: Id223b9fc0ac1aa9a5a5aeb4af63da04f2cc7574b Reviewed-on: https://review.haiku-os.org/c/haiku/+/6400 Reviewed-by: John Scipione <[email protected]> Reviewed-by: Rene Gollent <[email protected]>
This commit is contained in:
@@ -29,7 +29,7 @@ static CliContext* sCurrentContext;
|
||||
|
||||
|
||||
struct CliContext::Event : DoublyLinkedListLinkImpl<CliContext::Event> {
|
||||
Event(int type, Thread* thread = NULL, TeamMemoryBlock* block = NULL,
|
||||
Event(int type, ::Thread* thread = NULL, TeamMemoryBlock* block = NULL,
|
||||
ExpressionInfo* info = NULL, status_t expressionResult = B_OK,
|
||||
ExpressionResult* expressionValue = NULL)
|
||||
:
|
||||
@@ -47,7 +47,7 @@ struct CliContext::Event : DoublyLinkedListLinkImpl<CliContext::Event> {
|
||||
return fType;
|
||||
}
|
||||
|
||||
Thread* GetThread() const
|
||||
::Thread* GetThread() const
|
||||
{
|
||||
return fThreadReference.Get();
|
||||
}
|
||||
@@ -75,7 +75,7 @@ struct CliContext::Event : DoublyLinkedListLinkImpl<CliContext::Event> {
|
||||
|
||||
private:
|
||||
int fType;
|
||||
BReference<Thread> fThreadReference;
|
||||
BReference< ::Thread> fThreadReference;
|
||||
BReference<TeamMemoryBlock> fMemoryBlockReference;
|
||||
BReference<ExpressionInfo> fExpressionInfo;
|
||||
status_t fExpressionResult;
|
||||
@@ -88,6 +88,7 @@ private:
|
||||
|
||||
CliContext::CliContext()
|
||||
:
|
||||
BLooper("CliContext"),
|
||||
fLock("CliContext"),
|
||||
fTeam(NULL),
|
||||
fListener(NULL),
|
||||
@@ -95,10 +96,8 @@ CliContext::CliContext()
|
||||
fEditLine(NULL),
|
||||
fHistory(NULL),
|
||||
fPrompt(NULL),
|
||||
fBlockingSemaphore(-1),
|
||||
fInputLoopWaitingForEvents(0),
|
||||
fEventsOccurred(0),
|
||||
fInputLoopWaiting(false),
|
||||
fWaitForEventSemaphore(-1),
|
||||
fEventOccurred(0),
|
||||
fTerminating(false),
|
||||
fStoppedThread(NULL),
|
||||
fCurrentThread(NULL),
|
||||
@@ -118,14 +117,16 @@ CliContext::~CliContext()
|
||||
Cleanup();
|
||||
sCurrentContext = NULL;
|
||||
|
||||
if (fBlockingSemaphore >= 0)
|
||||
delete_sem(fBlockingSemaphore);
|
||||
if (fWaitForEventSemaphore >= 0)
|
||||
delete_sem(fWaitForEventSemaphore);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CliContext::Init(Team* team, UserInterfaceListener* listener)
|
||||
CliContext::Init(::Team* team, UserInterfaceListener* listener)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
fTeam = team;
|
||||
fListener = listener;
|
||||
|
||||
@@ -135,9 +136,9 @@ CliContext::Init(Team* team, UserInterfaceListener* listener)
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
fBlockingSemaphore = create_sem(0, "CliContext block");
|
||||
if (fBlockingSemaphore < 0)
|
||||
return fBlockingSemaphore;
|
||||
fWaitForEventSemaphore = create_sem(0, "CliContext wait for event");
|
||||
if (fWaitForEventSemaphore < 0)
|
||||
return fWaitForEventSemaphore;
|
||||
|
||||
fEditLine = el_init("Debugger", stdin, stdout, stderr);
|
||||
if (fEditLine == NULL)
|
||||
@@ -171,11 +172,9 @@ CliContext::Init(Team* team, UserInterfaceListener* listener)
|
||||
void
|
||||
CliContext::Cleanup()
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
Terminating();
|
||||
|
||||
while (Event* event = fPendingEvents.RemoveHead())
|
||||
delete event;
|
||||
|
||||
if (fEditLine != NULL) {
|
||||
el_end(fEditLine);
|
||||
fEditLine = NULL;
|
||||
@@ -208,13 +207,16 @@ CliContext::Cleanup()
|
||||
}
|
||||
|
||||
|
||||
// TODO: Use the lifecycle methods of BLooper instead
|
||||
void
|
||||
CliContext::Terminating()
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
fTerminating = true;
|
||||
_SignalInputLoop(EVENT_QUIT);
|
||||
|
||||
BMessage message(MSG_QUIT);
|
||||
PostMessage(&message);
|
||||
|
||||
// TODO: Signal the input loop, should it be in PromptUser()!
|
||||
}
|
||||
@@ -223,12 +225,13 @@ CliContext::Terminating()
|
||||
thread_id
|
||||
CliContext::CurrentThreadID() const
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
return fCurrentThread != NULL ? fCurrentThread->ID() : -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::SetCurrentThread(Thread* thread)
|
||||
CliContext::SetCurrentThread(::Thread* thread)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
@@ -262,7 +265,8 @@ CliContext::SetCurrentThread(Thread* thread)
|
||||
void
|
||||
CliContext::PrintCurrentThread()
|
||||
{
|
||||
AutoLocker<Team> teamLocker(fTeam);
|
||||
AutoLocker< ::Team> teamLocker(fTeam);
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
if (fCurrentThread != NULL) {
|
||||
printf("current thread: %" B_PRId32 " \"%s\"\n", fCurrentThread->ID(),
|
||||
@@ -294,11 +298,12 @@ status_t
|
||||
CliContext::EvaluateExpression(const char* expression,
|
||||
SourceLanguage* language, target_addr_t& address)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
fExpressionInfo->SetTo(expression);
|
||||
|
||||
fListener->ExpressionEvaluationRequested(
|
||||
language, fExpressionInfo);
|
||||
WaitForEvents(CliContext::EVENT_EXPRESSION_EVALUATED);
|
||||
_WaitForEvent(MSG_EXPRESSION_EVALUATED);
|
||||
if (fTerminating)
|
||||
return B_INTERRUPTED;
|
||||
|
||||
@@ -329,9 +334,10 @@ CliContext::EvaluateExpression(const char* expression,
|
||||
status_t
|
||||
CliContext::GetMemoryBlock(target_addr_t address, TeamMemoryBlock*& block)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
if (fCurrentBlock == NULL || !fCurrentBlock->Contains(address)) {
|
||||
GetUserInterfaceListener()->InspectRequested(address, this);
|
||||
WaitForEvents(CliContext::EVENT_TEAM_MEMORY_BLOCK_RETRIEVED);
|
||||
_WaitForEvent(MSG_TEAM_MEMORY_BLOCK_RETRIEVED);
|
||||
if (fTerminating)
|
||||
return B_INTERRUPTED;
|
||||
}
|
||||
@@ -351,8 +357,6 @@ CliContext::PromptUser(const char* prompt)
|
||||
|
||||
fPrompt = NULL;
|
||||
|
||||
ProcessPendingEvents();
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
@@ -368,14 +372,12 @@ CliContext::AddLineToInputHistory(const char* line)
|
||||
void
|
||||
CliContext::QuitSession(bool killTeam)
|
||||
{
|
||||
_PrepareToWaitForEvents(EVENT_QUIT);
|
||||
|
||||
fListener->UserInterfaceQuitRequested(
|
||||
killTeam
|
||||
? UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM
|
||||
: UserInterfaceListener::QUIT_OPTION_ASK_RESUME_TEAM);
|
||||
|
||||
_WaitForEvents();
|
||||
WaitForEvent(MSG_QUIT);
|
||||
}
|
||||
|
||||
|
||||
@@ -384,19 +386,10 @@ CliContext::WaitForThreadOrUser()
|
||||
{
|
||||
// TODO: Deal with SIGINT as well!
|
||||
|
||||
// if no thread has been stopped, wait till one is
|
||||
while (fStoppedThread == NULL) {
|
||||
_PrepareToWaitForEvents(
|
||||
EVENT_USER_INTERRUPT | EVENT_THREAD_STATE_CHANGED);
|
||||
uint32 events = _WaitForEvents();
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
ProcessPendingEvents();
|
||||
// updates fStoppedThread if any thread has been stopped
|
||||
|
||||
if ((events & EVENT_QUIT) != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (fStoppedThread == NULL)
|
||||
_WaitForEvent(MSG_THREAD_STATE_CHANGED);
|
||||
|
||||
if (fCurrentThread == NULL)
|
||||
SetCurrentThread(fStoppedThread);
|
||||
@@ -404,116 +397,138 @@ CliContext::WaitForThreadOrUser()
|
||||
|
||||
|
||||
void
|
||||
CliContext::WaitForEvents(int32 eventMask)
|
||||
{
|
||||
for (;;) {
|
||||
_PrepareToWaitForEvents(eventMask | EVENT_USER_INTERRUPT);
|
||||
uint32 events = fEventsOccurred;
|
||||
if ((events & eventMask) == 0) {
|
||||
events = _WaitForEvents();
|
||||
}
|
||||
|
||||
if ((events & EVENT_QUIT) != 0 || (events & eventMask) != 0) {
|
||||
_SignalInputLoop(eventMask);
|
||||
ProcessPendingEvents();
|
||||
return;
|
||||
}
|
||||
}
|
||||
CliContext::WaitForEvent(uint32 event) {
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
_WaitForEvent(event);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ProcessPendingEvents()
|
||||
CliContext::MessageReceived(BMessage* message)
|
||||
{
|
||||
AutoLocker<Team> teamLocker(fTeam);
|
||||
fLock.Lock();
|
||||
|
||||
for (;;) {
|
||||
// get the next event
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
Event* event = fPendingEvents.RemoveHead();
|
||||
locker.Unlock();
|
||||
if (event == NULL)
|
||||
int32 threadID;
|
||||
message->FindInt32("thread", &threadID);
|
||||
|
||||
const char* threadName;
|
||||
message->FindString("threadName", &threadName);
|
||||
|
||||
switch (message->what) {
|
||||
case MSG_THREAD_ADDED:
|
||||
printf("[new thread: %" B_PRId32 " \"%s\"]\n", threadID,
|
||||
threadName);
|
||||
break;
|
||||
ObjectDeleter<Event> eventDeleter(event);
|
||||
case MSG_THREAD_REMOVED:
|
||||
printf("[thread terminated: %" B_PRId32 " \"%s\"]\n",
|
||||
threadID, threadName);
|
||||
break;
|
||||
case MSG_THREAD_STATE_CHANGED:
|
||||
{
|
||||
AutoLocker< ::Team> locker(fTeam);
|
||||
::Thread* thread = fTeam->ThreadByID(threadID);
|
||||
|
||||
// process the event
|
||||
Thread* thread = event->GetThread();
|
||||
|
||||
switch (event->Type()) {
|
||||
case EVENT_QUIT:
|
||||
case EVENT_DEBUG_REPORT_CHANGED:
|
||||
case EVENT_USER_INTERRUPT:
|
||||
break;
|
||||
case EVENT_THREAD_ADDED:
|
||||
printf("[new thread: %" B_PRId32 " \"%s\"]\n", thread->ID(),
|
||||
thread->Name());
|
||||
break;
|
||||
case EVENT_THREAD_REMOVED:
|
||||
printf("[thread terminated: %" B_PRId32 " \"%s\"]\n",
|
||||
thread->ID(), thread->Name());
|
||||
break;
|
||||
case EVENT_THREAD_STATE_CHANGED:
|
||||
if (thread->State() == THREAD_STATE_STOPPED) {
|
||||
printf("[thread stopped: %" B_PRId32 " \"%s\"]\n",
|
||||
thread->ID(), thread->Name());
|
||||
fStoppedThread.SetTo(thread);
|
||||
} else {
|
||||
fStoppedThread = NULL;
|
||||
}
|
||||
break;
|
||||
case EVENT_THREAD_STACK_TRACE_CHANGED:
|
||||
if (thread == fCurrentThread) {
|
||||
fCurrentStackTrace = thread->GetStackTrace();
|
||||
fCurrentStackTrace->AcquireReference();
|
||||
SetCurrentStackFrameIndex(0);
|
||||
}
|
||||
break;
|
||||
case EVENT_TEAM_MEMORY_BLOCK_RETRIEVED:
|
||||
if (fCurrentBlock != NULL) {
|
||||
fCurrentBlock->ReleaseReference();
|
||||
fCurrentBlock = NULL;
|
||||
}
|
||||
fCurrentBlock = event->GetMemoryBlock();
|
||||
break;
|
||||
case EVENT_EXPRESSION_EVALUATED:
|
||||
fExpressionResult = event->GetExpressionResult();
|
||||
if (fExpressionValue != NULL) {
|
||||
fExpressionValue->ReleaseReference();
|
||||
fExpressionValue = NULL;
|
||||
}
|
||||
fExpressionValue = event->GetExpressionValue();
|
||||
if (fExpressionValue != NULL)
|
||||
fExpressionValue->AcquireReference();
|
||||
break;
|
||||
if (thread->State() == THREAD_STATE_STOPPED) {
|
||||
printf("[thread stopped: %" B_PRId32 " \"%s\"]\n",
|
||||
threadID, threadName);
|
||||
fStoppedThread.SetTo(thread);
|
||||
} else {
|
||||
fStoppedThread = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSG_THREAD_STACK_TRACE_CHANGED:
|
||||
if (threadID == fCurrentThread->ID()) {
|
||||
AutoLocker< ::Team> locker(fTeam);
|
||||
::Thread* thread = fTeam->ThreadByID(threadID);
|
||||
|
||||
fCurrentStackTrace = thread->GetStackTrace();
|
||||
fCurrentStackTrace->AcquireReference();
|
||||
SetCurrentStackFrameIndex(0);
|
||||
}
|
||||
break;
|
||||
case MSG_TEAM_MEMORY_BLOCK_RETRIEVED:
|
||||
{
|
||||
TeamMemoryBlock* block = NULL;
|
||||
if (message->FindPointer("block",
|
||||
reinterpret_cast<void **>(&block)) != B_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (fCurrentBlock != NULL) {
|
||||
fCurrentBlock->ReleaseReference();
|
||||
}
|
||||
|
||||
// reference acquired in MemoryBlockRetrieved
|
||||
fCurrentBlock = block;
|
||||
break;
|
||||
}
|
||||
case MSG_EXPRESSION_EVALUATED:
|
||||
{
|
||||
status_t result;
|
||||
if (message->FindInt32("result", &result) != B_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
fExpressionResult = result;
|
||||
|
||||
ExpressionResult* value = NULL;
|
||||
message->FindPointer("value", reinterpret_cast<void**>(&value));
|
||||
|
||||
if (fExpressionValue != NULL) {
|
||||
fExpressionValue->ReleaseReference();
|
||||
}
|
||||
|
||||
// reference acquired in ExpressionEvaluated
|
||||
fExpressionValue = value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLooper::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
|
||||
fEventOccurred = message->what;
|
||||
|
||||
fLock.Unlock();
|
||||
|
||||
release_sem(fWaitForEventSemaphore);
|
||||
// all of the code that was waiting on the semaphore runs
|
||||
acquire_sem(fWaitForEventSemaphore);
|
||||
|
||||
fLock.Lock();
|
||||
fEventOccurred = 0;
|
||||
fLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ThreadAdded(const Team::ThreadEvent& threadEvent)
|
||||
{
|
||||
_QueueEvent(
|
||||
new(std::nothrow) Event(EVENT_THREAD_ADDED, threadEvent.GetThread()));
|
||||
_SignalInputLoop(EVENT_THREAD_ADDED);
|
||||
BMessage message(MSG_THREAD_ADDED);
|
||||
message.AddInt32("thread", threadEvent.GetThread()->ID());
|
||||
message.AddString("threadName", threadEvent.GetThread()->Name());
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ThreadRemoved(const Team::ThreadEvent& threadEvent)
|
||||
{
|
||||
_QueueEvent(
|
||||
new(std::nothrow) Event(EVENT_THREAD_REMOVED, threadEvent.GetThread()));
|
||||
_SignalInputLoop(EVENT_THREAD_REMOVED);
|
||||
BMessage message(MSG_THREAD_REMOVED);
|
||||
message.AddInt32("thread", threadEvent.GetThread()->ID());
|
||||
message.AddString("threadName", threadEvent.GetThread()->Name());
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ThreadStateChanged(const Team::ThreadEvent& threadEvent)
|
||||
{
|
||||
_QueueEvent(
|
||||
new(std::nothrow) Event(EVENT_THREAD_STATE_CHANGED, threadEvent.GetThread()));
|
||||
_SignalInputLoop(EVENT_THREAD_STATE_CHANGED);
|
||||
BMessage message(MSG_THREAD_STATE_CHANGED);
|
||||
message.AddInt32("thread", threadEvent.GetThread()->ID());
|
||||
message.AddString("threadName", threadEvent.GetThread()->Name());
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
@@ -523,10 +538,10 @@ 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);
|
||||
BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
|
||||
message.AddInt32("thread", threadEvent.GetThread()->ID());
|
||||
message.AddString("threadName", threadEvent.GetThread()->Name());
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
@@ -534,10 +549,15 @@ void
|
||||
CliContext::ExpressionEvaluated(ExpressionInfo* info, status_t result,
|
||||
ExpressionResult* value)
|
||||
{
|
||||
_QueueEvent(
|
||||
new(std::nothrow) Event(EVENT_EXPRESSION_EVALUATED,
|
||||
NULL, NULL, info, result, value));
|
||||
_SignalInputLoop(EVENT_EXPRESSION_EVALUATED);
|
||||
BMessage message(MSG_EXPRESSION_EVALUATED);
|
||||
message.AddInt32("result", result);
|
||||
|
||||
if (value != NULL) {
|
||||
value->AcquireReference();
|
||||
message.AddPointer("value", value);
|
||||
}
|
||||
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
@@ -551,9 +571,6 @@ CliContext::DebugReportChanged(const Team::DebugReportEvent& event)
|
||||
fprintf(stderr, "Failed to write debug report: %s\n", strerror(
|
||||
event.GetFinalStatus()));
|
||||
}
|
||||
|
||||
_QueueEvent(new(std::nothrow) Event(EVENT_DEBUG_REPORT_CHANGED));
|
||||
_SignalInputLoop(EVENT_DEBUG_REPORT_CHANGED);
|
||||
}
|
||||
|
||||
|
||||
@@ -562,19 +579,18 @@ CliContext::CoreFileChanged(const Team::CoreFileChangedEvent& event)
|
||||
{
|
||||
printf("Successfully saved core file to %s\n",
|
||||
event.GetTargetPath());
|
||||
|
||||
_QueueEvent(new(std::nothrow) Event(EVENT_CORE_FILE_CHANGED));
|
||||
_SignalInputLoop(EVENT_CORE_FILE_CHANGED);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::MemoryBlockRetrieved(TeamMemoryBlock* block)
|
||||
{
|
||||
_QueueEvent(
|
||||
new(std::nothrow) Event(EVENT_TEAM_MEMORY_BLOCK_RETRIEVED,
|
||||
NULL, block));
|
||||
_SignalInputLoop(EVENT_TEAM_MEMORY_BLOCK_RETRIEVED);
|
||||
if (block != NULL)
|
||||
block->AcquireReference();
|
||||
|
||||
BMessage message(MSG_TEAM_MEMORY_BLOCK_RETRIEVED);
|
||||
message.AddPointer("block", block);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
@@ -582,92 +598,32 @@ void
|
||||
CliContext::ValueNodeChanged(ValueNodeChild* nodeChild, ValueNode* oldNode,
|
||||
ValueNode* newNode)
|
||||
{
|
||||
_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
|
||||
BMessage message(MSG_VALUE_NODE_CHANGED);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ValueNodeChildrenCreated(ValueNode* node)
|
||||
{
|
||||
_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
|
||||
BMessage message(MSG_VALUE_NODE_CHANGED);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ValueNodeChildrenDeleted(ValueNode* node)
|
||||
{
|
||||
_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
|
||||
BMessage message(MSG_VALUE_NODE_CHANGED);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ValueNodeValueChanged(ValueNode* oldNode)
|
||||
{
|
||||
_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::_QueueEvent(Event* event)
|
||||
{
|
||||
if (event == NULL) {
|
||||
// no memory -- can't do anything about it
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
fPendingEvents.Add(event);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::_PrepareToWaitForEvents(uint32 eventMask)
|
||||
{
|
||||
// Set the events we're going to wait for -- always wait for "quit".
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
fInputLoopWaitingForEvents = eventMask | EVENT_QUIT;
|
||||
fEventsOccurred = fTerminating ? EVENT_QUIT : 0;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
CliContext::_WaitForEvents()
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
if (fEventsOccurred == 0) {
|
||||
sem_id blockingSemaphore = fBlockingSemaphore;
|
||||
fInputLoopWaiting = true;
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
while (acquire_sem(blockingSemaphore) == B_INTERRUPTED) {
|
||||
}
|
||||
|
||||
locker.Lock();
|
||||
}
|
||||
|
||||
uint32 events = fEventsOccurred;
|
||||
fEventsOccurred = 0;
|
||||
return events;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::_SignalInputLoop(uint32 events)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
if ((fInputLoopWaitingForEvents & events) == 0)
|
||||
return;
|
||||
|
||||
fEventsOccurred = fInputLoopWaitingForEvents & events;
|
||||
fInputLoopWaitingForEvents = 0;
|
||||
|
||||
if (fInputLoopWaiting) {
|
||||
fInputLoopWaiting = false;
|
||||
release_sem(fBlockingSemaphore);
|
||||
}
|
||||
BMessage message(MSG_VALUE_NODE_CHANGED);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
@@ -676,3 +632,19 @@ CliContext::_GetPrompt(EditLine* editLine)
|
||||
{
|
||||
return sCurrentContext != NULL ? sCurrentContext->fPrompt : NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::_WaitForEvent(uint32 event) {
|
||||
if (fTerminating)
|
||||
return;
|
||||
|
||||
do {
|
||||
fLock.Unlock();
|
||||
while (acquire_sem(fWaitForEventSemaphore) == B_INTERRUPTED) {
|
||||
}
|
||||
fLock.Lock();
|
||||
release_sem(fWaitForEventSemaphore);
|
||||
} while (fEventOccurred != event && !fTerminating);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <histedit.h>
|
||||
|
||||
#include <Locker.h>
|
||||
#include <Looper.h>
|
||||
|
||||
#include "ExpressionInfo.h"
|
||||
#include "Team.h"
|
||||
@@ -31,27 +32,28 @@ class ValueNodeManager;
|
||||
class CliContext : private Team::Listener,
|
||||
public TeamMemoryBlock::Listener,
|
||||
public ExpressionInfo::Listener,
|
||||
private ValueNodeContainer::Listener {
|
||||
private ValueNodeContainer::Listener,
|
||||
public BLooper {
|
||||
public:
|
||||
enum {
|
||||
EVENT_QUIT = 0x01,
|
||||
EVENT_USER_INTERRUPT = 0x02,
|
||||
EVENT_THREAD_ADDED = 0x04,
|
||||
EVENT_THREAD_REMOVED = 0x08,
|
||||
EVENT_THREAD_STATE_CHANGED = 0x10,
|
||||
EVENT_THREAD_STACK_TRACE_CHANGED = 0x20,
|
||||
EVENT_VALUE_NODE_CHANGED = 0x40,
|
||||
EVENT_TEAM_MEMORY_BLOCK_RETRIEVED = 0x80,
|
||||
EVENT_EXPRESSION_EVALUATED = 0x100,
|
||||
EVENT_DEBUG_REPORT_CHANGED = 0x200,
|
||||
EVENT_CORE_FILE_CHANGED = 0x400
|
||||
MSG_QUIT = 'quit',
|
||||
MSG_USER_INTERRUPT = 'uint',
|
||||
MSG_THREAD_ADDED = 'thad',
|
||||
MSG_THREAD_REMOVED = 'thar',
|
||||
MSG_THREAD_STATE_CHANGED = 'tsch',
|
||||
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc',
|
||||
MSG_VALUE_NODE_CHANGED = 'vnch',
|
||||
MSG_TEAM_MEMORY_BLOCK_RETRIEVED = 'tmbr',
|
||||
MSG_EXPRESSION_EVALUATED = 'exev',
|
||||
MSG_DEBUG_REPORT_CHANGED = 'drch',
|
||||
MSG_CORE_FILE_CHANGED = 'cfch'
|
||||
};
|
||||
|
||||
public:
|
||||
CliContext();
|
||||
~CliContext();
|
||||
|
||||
status_t Init(Team* team,
|
||||
status_t Init(::Team* team,
|
||||
UserInterfaceListener* listener);
|
||||
void Cleanup();
|
||||
|
||||
@@ -59,9 +61,11 @@ public:
|
||||
|
||||
bool IsTerminating() const { return fTerminating; }
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
// service methods for the input loop thread follow
|
||||
|
||||
Team* GetTeam() const { return fTeam; }
|
||||
::Team* GetTeam() const { return fTeam; }
|
||||
UserInterfaceListener* GetUserInterfaceListener() const
|
||||
{ return fListener; }
|
||||
ValueNodeManager* GetValueNodeManager() const
|
||||
@@ -69,9 +73,9 @@ public:
|
||||
StackTrace* GetStackTrace() const
|
||||
{ return fCurrentStackTrace; }
|
||||
|
||||
Thread* CurrentThread() const { return fCurrentThread; }
|
||||
::Thread* CurrentThread() const { return fCurrentThread; }
|
||||
thread_id CurrentThreadID() const;
|
||||
void SetCurrentThread(Thread* thread);
|
||||
void SetCurrentThread(::Thread* thread);
|
||||
void PrintCurrentThread();
|
||||
|
||||
int32 CurrentStackFrameIndex() const
|
||||
@@ -90,8 +94,7 @@ public:
|
||||
void QuitSession(bool killTeam);
|
||||
|
||||
void WaitForThreadOrUser();
|
||||
void WaitForEvents(int32 eventMask);
|
||||
void ProcessPendingEvents();
|
||||
void WaitForEvent(uint32 event);
|
||||
|
||||
private:
|
||||
struct Event;
|
||||
@@ -129,30 +132,23 @@ private:
|
||||
virtual void ValueNodeValueChanged(ValueNode* node);
|
||||
|
||||
private:
|
||||
void _QueueEvent(Event* event);
|
||||
|
||||
void _PrepareToWaitForEvents(uint32 eventMask);
|
||||
uint32 _WaitForEvents();
|
||||
void _SignalInputLoop(uint32 events);
|
||||
|
||||
static const char* _GetPrompt(EditLine* editLine);
|
||||
void _WaitForEvent(uint32 event);
|
||||
|
||||
private:
|
||||
BLocker fLock;
|
||||
Team* fTeam;
|
||||
mutable BLocker fLock;
|
||||
::Team* fTeam;
|
||||
UserInterfaceListener* fListener;
|
||||
ValueNodeManager* fNodeManager;
|
||||
EditLine* fEditLine;
|
||||
History* fHistory;
|
||||
const char* fPrompt;
|
||||
sem_id fBlockingSemaphore;
|
||||
uint32 fInputLoopWaitingForEvents;
|
||||
uint32 fEventsOccurred;
|
||||
bool fInputLoopWaiting;
|
||||
sem_id fWaitForEventSemaphore;
|
||||
uint32 fEventOccurred;
|
||||
volatile bool fTerminating;
|
||||
|
||||
BReference<Thread> fStoppedThread;
|
||||
Thread* fCurrentThread;
|
||||
BReference< ::Thread> fStoppedThread;
|
||||
::Thread* fCurrentThread;
|
||||
StackTrace* fCurrentStackTrace;
|
||||
int32 fCurrentStackFrameIndex;
|
||||
TeamMemoryBlock* fCurrentBlock;
|
||||
@@ -160,8 +156,6 @@ private:
|
||||
ExpressionInfo* fExpressionInfo;
|
||||
status_t fExpressionResult;
|
||||
ExpressionResult* fExpressionValue;
|
||||
|
||||
EventList fPendingEvents;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ private:
|
||||
|
||||
CommandLineUserInterface::CommandLineUserInterface()
|
||||
:
|
||||
fContext(new CliContext()),
|
||||
fCommands(20, true),
|
||||
fShowSemaphore(-1),
|
||||
fShown(false),
|
||||
@@ -122,7 +123,7 @@ CommandLineUserInterface::ID() const
|
||||
status_t
|
||||
CommandLineUserInterface::Init(Team* team, UserInterfaceListener* listener)
|
||||
{
|
||||
status_t error = fContext.Init(team, listener);
|
||||
status_t error = fContext->Init(team, listener);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
@@ -152,7 +153,7 @@ CommandLineUserInterface::Terminate()
|
||||
fTerminating = true;
|
||||
|
||||
if (fShown) {
|
||||
fContext.Terminating();
|
||||
fContext->Terminating();
|
||||
|
||||
// Wait for input loop to finish.
|
||||
while (acquire_sem(fShowSemaphore) == B_INTERRUPTED) {
|
||||
@@ -163,7 +164,10 @@ CommandLineUserInterface::Terminate()
|
||||
fShowSemaphore = -1;
|
||||
}
|
||||
|
||||
fContext.Cleanup();
|
||||
fContext->Cleanup();
|
||||
|
||||
BMessage message(B_QUIT_REQUESTED);
|
||||
fContext->PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
@@ -236,6 +240,7 @@ CommandLineUserInterface::Run()
|
||||
if (error != B_OK)
|
||||
return;
|
||||
|
||||
fContext->Run();
|
||||
_InputLoop();
|
||||
// Release the Show() semaphore to signal Terminate().
|
||||
release_sem(fShowSemaphore);
|
||||
@@ -248,21 +253,19 @@ CommandLineUserInterface::_InputLoop()
|
||||
thread_id currentThread = -1;
|
||||
|
||||
while (!fTerminating) {
|
||||
fContext.ProcessPendingEvents();
|
||||
|
||||
// Wait for a thread or Ctrl-C.
|
||||
fContext.WaitForThreadOrUser();
|
||||
if (fContext.IsTerminating())
|
||||
fContext->WaitForThreadOrUser();
|
||||
if (fContext->IsTerminating())
|
||||
break;
|
||||
|
||||
// Print the active thread, if it changed.
|
||||
if (fContext.CurrentThreadID() != currentThread) {
|
||||
fContext.PrintCurrentThread();
|
||||
currentThread = fContext.CurrentThreadID();
|
||||
if (fContext->CurrentThreadID() != currentThread) {
|
||||
fContext->PrintCurrentThread();
|
||||
currentThread = fContext->CurrentThreadID();
|
||||
}
|
||||
|
||||
// read a command line
|
||||
const char* line = fContext.PromptUser(kDebuggerPrompt);
|
||||
const char* line = fContext->PromptUser(kDebuggerPrompt);
|
||||
if (line == NULL)
|
||||
break;
|
||||
|
||||
@@ -288,7 +291,7 @@ CommandLineUserInterface::_InputLoop()
|
||||
continue;
|
||||
|
||||
// add line to history
|
||||
fContext.AddLineToInputHistory(line);
|
||||
fContext->AddLineToInputHistory(line);
|
||||
|
||||
// execute command
|
||||
_ExecuteCommand(args.ArgumentCount(), args.Arguments());
|
||||
@@ -369,7 +372,7 @@ CommandLineUserInterface::_ExecuteCommand(int argc, const char* const* argv)
|
||||
{
|
||||
CommandEntry* commandEntry = _FindCommand(argv[0]);
|
||||
if (commandEntry != NULL)
|
||||
commandEntry->Command()->Execute(argc, argv, fContext);
|
||||
commandEntry->Command()->Execute(argc, argv, *fContext);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
const CommandEntry* command2);
|
||||
|
||||
private:
|
||||
CliContext fContext;
|
||||
CliContext* fContext;
|
||||
CommandList fCommands;
|
||||
sem_id fShowSemaphore;
|
||||
bool fShown;
|
||||
|
||||
@@ -119,7 +119,7 @@ CliPrintVariableCommand::_ResolveValueIfNeeded(ValueNode* node,
|
||||
while (node->LocationAndValueResolutionState()
|
||||
== VALUE_NODE_UNRESOLVED) {
|
||||
containerLocker.Unlock();
|
||||
context.WaitForEvents(CliContext::EVENT_VALUE_NODE_CHANGED);
|
||||
context.WaitForEvent(CliContext::MSG_VALUE_NODE_CHANGED);
|
||||
containerLocker.Lock();
|
||||
if (context.IsTerminating())
|
||||
return B_ERROR;
|
||||
|
||||
@@ -46,7 +46,7 @@ CliStackTraceCommand::Execute(int argc, const char* const* argv,
|
||||
// get its stack trace
|
||||
StackTrace* stackTrace = thread->GetStackTrace();
|
||||
while (stackTrace == NULL) {
|
||||
context.WaitForEvents(CliContext::EVENT_THREAD_STACK_TRACE_CHANGED);
|
||||
context.WaitForEvent(CliContext::MSG_THREAD_STACK_TRACE_CHANGED);
|
||||
if (context.IsTerminating())
|
||||
return;
|
||||
stackTrace = thread->GetStackTrace();
|
||||
|
||||
Reference in New Issue
Block a user