1d0ef7540SIngo Weinhold/*
27bdeef54SRene Gollent * Copyright 2012-2016, Rene Gollent, rene@gollent.com.
3d0ef7540SIngo Weinhold * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
4d0ef7540SIngo Weinhold * Distributed under the terms of the MIT License.
5d0ef7540SIngo Weinhold */
6d0ef7540SIngo Weinhold
7d0ef7540SIngo Weinhold
8d0ef7540SIngo Weinhold#include "CliContext.h"
9d0ef7540SIngo Weinhold
1086b1039bSIngo Weinhold#include <AutoDeleter.h>
118fe9f8b2SIngo Weinhold#include <AutoLocker.h>
128fe9f8b2SIngo Weinhold
131325ad5fSRene Gollent#include "StackTrace.h"
14d0ef7540SIngo Weinhold#include "UserInterface.h"
151325ad5fSRene Gollent#include "ValueNodeManager.h"
1681c848a1SRene Gollent#include "Variable.h"
1781c848a1SRene Gollent
18d0ef7540SIngo Weinhold
198fe9f8b2SIngo Weinhold// NOTE: This is a simple work-around for EditLine not having any kind of user
208fe9f8b2SIngo Weinhold// data field. Hence in _GetPrompt() we don't have access to the context object.
218fe9f8b2SIngo Weinhold// ATM only one CLI is possible in Debugger, so a static variable works well
228fe9f8b2SIngo Weinhold// enough. Should that ever change, we would need a thread-safe
238fe9f8b2SIngo Weinhold// EditLine* -> CliContext* map.
248fe9f8b2SIngo Weinholdstatic CliContext* sCurrentContext;
258fe9f8b2SIngo Weinhold
268fe9f8b2SIngo Weinhold
2786b1039bSIngo Weinhold// #pragma mark - Event
2886b1039bSIngo Weinhold
2986b1039bSIngo Weinhold
3086b1039bSIngo Weinholdstruct CliContext::Event : DoublyLinkedListLinkImpl<CliContext::Event> {
3138258751SRene Gollent	Event(int type, Thread* thread = NULL, TeamMemoryBlock* block = NULL,
32d1c9ffedSRene Gollent		ExpressionInfo* info = NULL, status_t expressionResult = B_OK,
3381c848a1SRene Gollent		ExpressionResult* expressionValue = NULL)
3486b1039bSIngo Weinhold		:
3586b1039bSIngo Weinhold		fType(type),
36c7f5dd62SRene Gollent		fThreadReference(thread),
3738258751SRene Gollent		fMemoryBlockReference(block),
38d1c9ffedSRene Gollent		fExpressionInfo(info),
3938258751SRene Gollent		fExpressionResult(expressionResult),
4038258751SRene Gollent		fExpressionValue(expressionValue)
4186b1039bSIngo Weinhold	{
4286b1039bSIngo Weinhold	}
4386b1039bSIngo Weinhold
4486b1039bSIngo Weinhold	int Type() const
4586b1039bSIngo Weinhold	{
4686b1039bSIngo Weinhold		return fType;
4786b1039bSIngo Weinhold	}
4886b1039bSIngo Weinhold
4986b1039bSIngo Weinhold	Thread* GetThread() const
5086b1039bSIngo Weinhold	{
5186b1039bSIngo Weinhold		return fThreadReference.Get();
5286b1039bSIngo Weinhold	}
5386b1039bSIngo Weinhold
54c7f5dd62SRene Gollent	TeamMemoryBlock* GetMemoryBlock() const
55c7f5dd62SRene Gollent	{
56c7f5dd62SRene Gollent		return fMemoryBlockReference.Get();
57c7f5dd62SRene Gollent	}
58c7f5dd62SRene Gollent
59d1c9ffedSRene Gollent	ExpressionInfo* GetExpressionInfo() const
6038258751SRene Gollent	{
61d1c9ffedSRene Gollent		return fExpressionInfo;
6238258751SRene Gollent	}
6338258751SRene Gollent
6438258751SRene Gollent	status_t GetExpressionResult() const
6538258751SRene Gollent	{
6638258751SRene Gollent		return fExpressionResult;
6738258751SRene Gollent	}
6838258751SRene Gollent
6981c848a1SRene Gollent	ExpressionResult* GetExpressionValue() const
7038258751SRene Gollent	{
7138258751SRene Gollent		return fExpressionValue.Get();
7238258751SRene Gollent	}
7338258751SRene Gollent
7438258751SRene Gollent
7586b1039bSIngo Weinholdprivate:
7686b1039bSIngo Weinhold	int					fType;
7786b1039bSIngo Weinhold	BReference<Thread>	fThreadReference;
78c7f5dd62SRene Gollent	BReference<TeamMemoryBlock> fMemoryBlockReference;
79d1c9ffedSRene Gollent	BReference<ExpressionInfo> fExpressionInfo;
8038258751SRene Gollent	status_t			fExpressionResult;
8181c848a1SRene Gollent	BReference<ExpressionResult> fExpressionValue;
8286b1039bSIngo Weinhold};
8386b1039bSIngo Weinhold
8486b1039bSIngo Weinhold
8586b1039bSIngo Weinhold// #pragma mark - CliContext
8686b1039bSIngo Weinhold
8786b1039bSIngo Weinhold
88d0ef7540SIngo WeinholdCliContext::CliContext()
89d0ef7540SIngo Weinhold	:
908fe9f8b2SIngo Weinhold	fLock("CliContext"),
91d0ef7540SIngo Weinhold	fTeam(NULL),
928fe9f8b2SIngo Weinhold	fListener(NULL),
931325ad5fSRene Gollent	fNodeManager(NULL),
948fe9f8b2SIngo Weinhold	fEditLine(NULL),
958fe9f8b2SIngo Weinhold	fHistory(NULL),
968fe9f8b2SIngo Weinhold	fPrompt(NULL),
978fe9f8b2SIngo Weinhold	fBlockingSemaphore(-1),
98d266c87dSIngo Weinhold	fInputLoopWaitingForEvents(0),
99d266c87dSIngo Weinhold	fEventsOccurred(0),
1008fe9f8b2SIngo Weinhold	fInputLoopWaiting(false),
10186b1039bSIngo Weinhold	fTerminating(false),
1021325ad5fSRene Gollent	fCurrentThread(NULL),
1031325ad5fSRene Gollent	fCurrentStackTrace(NULL),
104c7f5dd62SRene Gollent	fCurrentStackFrameIndex(-1),
10538258751SRene Gollent	fCurrentBlock(NULL),
106d1c9ffedSRene Gollent	fExpressionInfo(NULL),
10738258751SRene Gollent	fExpressionResult(B_OK),
10838258751SRene Gollent	fExpressionValue(NULL)
109d0ef7540SIngo Weinhold{
1108fe9f8b2SIngo Weinhold	sCurrentContext = this;
111d0ef7540SIngo Weinhold}
112d0ef7540SIngo Weinhold
113d266c87dSIngo Weinhold
1148fe9f8b2SIngo WeinholdCliContext::~CliContext()
1158fe9f8b2SIngo Weinhold{
1168fe9f8b2SIngo Weinhold	Cleanup();
1178fe9f8b2SIngo Weinhold	sCurrentContext = NULL;
118d266c87dSIngo Weinhold
119d266c87dSIngo Weinhold	if (fBlockingSemaphore >= 0)
120d266c87dSIngo Weinhold		delete_sem(fBlockingSemaphore);
1218fe9f8b2SIngo Weinhold}
122d0ef7540SIngo Weinhold
1238fe9f8b2SIngo Weinhold
1248fe9f8b2SIngo Weinholdstatus_t
125d0ef7540SIngo WeinholdCliContext::Init(Team* team, UserInterfaceListener* listener)
126d0ef7540SIngo Weinhold{
127d0ef7540SIngo Weinhold	fTeam = team;
128d0ef7540SIngo Weinhold	fListener = listener;
1298fe9f8b2SIngo Weinhold
130d266c87dSIngo Weinhold	fTeam->AddListener(this);
131d266c87dSIngo Weinhold
1328fe9f8b2SIngo Weinhold	status_t error = fLock.InitCheck();
1338fe9f8b2SIngo Weinhold	if (error != B_OK)
1348fe9f8b2SIngo Weinhold		return error;
1358fe9f8b2SIngo Weinhold
1368fe9f8b2SIngo Weinhold	fBlockingSemaphore = create_sem(0, "CliContext block");
1378fe9f8b2SIngo Weinhold	if (fBlockingSemaphore < 0)
1388fe9f8b2SIngo Weinhold		return fBlockingSemaphore;
1398fe9f8b2SIngo Weinhold
1408fe9f8b2SIngo Weinhold	fEditLine = el_init("Debugger", stdin, stdout, stderr);
1418fe9f8b2SIngo Weinhold	if (fEditLine == NULL)
1428fe9f8b2SIngo Weinhold		return B_ERROR;
1438fe9f8b2SIngo Weinhold
1448fe9f8b2SIngo Weinhold	fHistory = history_init();
1458fe9f8b2SIngo Weinhold	if (fHistory == NULL)
1468fe9f8b2SIngo Weinhold		return B_ERROR;
1478fe9f8b2SIngo Weinhold
1488fe9f8b2SIngo Weinhold	HistEvent historyEvent;
1498fe9f8b2SIngo Weinhold	history(fHistory, &historyEvent, H_SETSIZE, 100);
1508fe9f8b2SIngo Weinhold
1518fe9f8b2SIngo Weinhold	el_set(fEditLine, EL_HIST, &history, fHistory);
1528fe9f8b2SIngo Weinhold	el_set(fEditLine, EL_EDITOR, "emacs");
1538fe9f8b2SIngo Weinhold	el_set(fEditLine, EL_PROMPT, &_GetPrompt);
1548fe9f8b2SIngo Weinhold
1551325ad5fSRene Gollent	fNodeManager = new(std::nothrow) ValueNodeManager();
1561325ad5fSRene Gollent	if (fNodeManager == NULL)
1571325ad5fSRene Gollent		return B_NO_MEMORY;
15803289a33SRene Gollent	fNodeManager->AddListener(this);
1591325ad5fSRene Gollent
160d1c9ffedSRene Gollent	fExpressionInfo = new(std::nothrow) ExpressionInfo();
161d1c9ffedSRene Gollent	if (fExpressionInfo == NULL)
162d1c9ffedSRene Gollent		return B_NO_MEMORY;
163d1c9ffedSRene Gollent	fExpressionInfo->AddListener(this);
164d1c9ffedSRene Gollent
1658fe9f8b2SIngo Weinhold	return B_OK;
166d0ef7540SIngo Weinhold}
167d0ef7540SIngo Weinhold
168d0ef7540SIngo Weinhold
169d0ef7540SIngo Weinholdvoid
1708fe9f8b2SIngo WeinholdCliContext::Cleanup()
1718fe9f8b2SIngo Weinhold{
1728fe9f8b2SIngo Weinhold	Terminating();
1738fe9f8b2SIngo Weinhold
17486b1039bSIngo Weinhold	while (Event* event = fPendingEvents.RemoveHead())
17586b1039bSIngo Weinhold		delete event;
17686b1039bSIngo Weinhold
1778fe9f8b2SIngo Weinhold	if (fEditLine != NULL) {
1788fe9f8b2SIngo Weinhold		el_end(fEditLine);
1798fe9f8b2SIngo Weinhold		fEditLine = NULL;
1808fe9f8b2SIngo Weinhold	}
1818fe9f8b2SIngo Weinhold
1828fe9f8b2SIngo Weinhold	if (fHistory != NULL) {
1838fe9f8b2SIngo Weinhold		history_end(fHistory);
1848fe9f8b2SIngo Weinhold		fHistory = NULL;
1858fe9f8b2SIngo Weinhold	}
186d266c87dSIngo Weinhold
187d266c87dSIngo Weinhold	if (fTeam != NULL) {
188d266c87dSIngo Weinhold		fTeam->RemoveListener(this);
189d266c87dSIngo Weinhold		fTeam = NULL;
190d266c87dSIngo Weinhold	}
1911325ad5fSRene Gollent
1921325ad5fSRene Gollent	if (fNodeManager != NULL) {
1931325ad5fSRene Gollent		fNodeManager->ReleaseReference();
1941325ad5fSRene Gollent		fNodeManager = NULL;
1951325ad5fSRene Gollent	}
196c7f5dd62SRene Gollent
197c7f5dd62SRene Gollent	if (fCurrentBlock != NULL) {
198c7f5dd62SRene Gollent		fCurrentBlock->ReleaseReference();
199c7f5dd62SRene Gollent		fCurrentBlock = NULL;
200c7f5dd62SRene Gollent	}
201d1c9ffedSRene Gollent
202d1c9ffedSRene Gollent	if (fExpressionInfo != NULL) {
203d1c9ffedSRene Gollent		fExpressionInfo->ReleaseReference();
204d1c9ffedSRene Gollent		fExpressionInfo = NULL;
205d1c9ffedSRene Gollent	}
2068fe9f8b2SIngo Weinhold}
2078fe9f8b2SIngo Weinhold
2088fe9f8b2SIngo Weinhold
2098fe9f8b2SIngo Weinholdvoid
2108fe9f8b2SIngo WeinholdCliContext::Terminating()
2118fe9f8b2SIngo Weinhold{
2128fe9f8b2SIngo Weinhold	AutoLocker<BLocker> locker(fLock);
2138fe9f8b2SIngo Weinhold
2148fe9f8b2SIngo Weinhold	fTerminating = true;
215d266c87dSIngo Weinhold	_SignalInputLoop(EVENT_QUIT);
2168fe9f8b2SIngo Weinhold
2178fe9f8b2SIngo Weinhold	// TODO: Signal the input loop, should it be in PromptUser()!
2188fe9f8b2SIngo Weinhold}
2198fe9f8b2SIngo Weinhold
2208fe9f8b2SIngo Weinhold
22186b1039bSIngo Weinholdthread_id
22286b1039bSIngo WeinholdCliContext::CurrentThreadID() const
22386b1039bSIngo Weinhold{
22486b1039bSIngo Weinhold	return fCurrentThread != NULL ? fCurrentThread->ID() : -1;
22586b1039bSIngo Weinhold}
22686b1039bSIngo Weinhold
22786b1039bSIngo Weinhold
22886b1039bSIngo Weinholdvoid
22986b1039bSIngo WeinholdCliContext::SetCurrentThread(Thread* thread)
23086b1039bSIngo Weinhold{
23186b1039bSIngo Weinhold	AutoLocker<BLocker> locker(fLock);
23286b1039bSIngo Weinhold
23386b1039bSIngo Weinhold	if (fCurrentThread != NULL)
23486b1039bSIngo Weinhold		fCurrentThread->ReleaseReference();
23586b1039bSIngo Weinhold
23686b1039bSIngo Weinhold	fCurrentThread = thread;
23786b1039bSIngo Weinhold
2381325ad5fSRene Gollent	if (fCurrentStackTrace != NULL) {
2391325ad5fSRene Gollent		fCurrentStackTrace->ReleaseReference();
2401325ad5fSRene Gollent		fCurrentStackTrace = NULL;
2411325ad5fSRene Gollent		fCurrentStackFrameIndex = -1;
2421325ad5fSRene Gollent		fNodeManager->SetStackFrame(NULL, NULL);
2431325ad5fSRene Gollent	}
2441325ad5fSRene Gollent
2451325ad5fSRene Gollent	if (fCurrentThread != NULL) {
24686b1039bSIngo Weinhold		fCurrentThread->AcquireReference();
2471325ad5fSRene Gollent		StackTrace* stackTrace = fCurrentThread->GetStackTrace();
2481325ad5fSRene Gollent		// if the thread's stack trace has already been loaded,
2491325ad5fSRene Gollent		// set it, otherwise we'll set it when we process the thread's
2501325ad5fSRene Gollent		// stack trace changed event.
2511325ad5fSRene Gollent		if (stackTrace != NULL) {
2521325ad5fSRene Gollent			fCurrentStackTrace = stackTrace;
2531325ad5fSRene Gollent			fCurrentStackTrace->AcquireReference();
2541325ad5fSRene Gollent			SetCurrentStackFrameIndex(0);
2551325ad5fSRene Gollent		}
2561325ad5fSRene Gollent	}
25786b1039bSIngo Weinhold}
25886b1039bSIngo Weinhold
25986b1039bSIngo Weinhold
26086b1039bSIngo Weinholdvoid
26186b1039bSIngo WeinholdCliContext::PrintCurrentThread()
26286b1039bSIngo Weinhold{
26386b1039bSIngo Weinhold	AutoLocker<Team> teamLocker(fTeam);
26486b1039bSIngo Weinhold
26586b1039bSIngo Weinhold	if (fCurrentThread != NULL) {
26686b1039bSIngo Weinhold		printf("current thread: %" B_PRId32 " \"%s\"\n", fCurrentThread->ID(),
26786b1039bSIngo Weinhold			fCurrentThread->Name());
26886b1039bSIngo Weinhold	} else
26986b1039bSIngo Weinhold		printf("no current thread\n");
27086b1039bSIngo Weinhold}
27186b1039bSIngo Weinhold
27286b1039bSIngo Weinhold
2731325ad5fSRene Gollentvoid
2741325ad5fSRene GollentCliContext::SetCurrentStackFrameIndex(int32 index)
2751325ad5fSRene Gollent{
2761325ad5fSRene Gollent	AutoLocker<BLocker> locker(fLock);
2771325ad5fSRene Gollent
2781325ad5fSRene Gollent	if (fCurrentStackTrace == NULL)
2791325ad5fSRene Gollent		return;
2801325ad5fSRene Gollent	else if (index < 0 || index >= fCurrentStackTrace->CountFrames())
2811325ad5fSRene Gollent		return;
2821325ad5fSRene Gollent
2831325ad5fSRene Gollent	fCurrentStackFrameIndex = index;
2841325ad5fSRene Gollent
2851325ad5fSRene Gollent	StackFrame* frame = fCurrentStackTrace->FrameAt(index);
2861325ad5fSRene Gollent	if (frame != NULL)
2871325ad5fSRene Gollent		fNodeManager->SetStackFrame(fCurrentThread, frame);
2881325ad5fSRene Gollent}
2891325ad5fSRene Gollent
2901325ad5fSRene Gollent
2918fe9f8b2SIngo Weinholdconst char*
2928fe9f8b2SIngo WeinholdCliContext::PromptUser(const char* prompt)
2938fe9f8b2SIngo Weinhold{
2948fe9f8b2SIngo Weinhold	fPrompt = prompt;
2958fe9f8b2SIngo Weinhold
2968fe9f8b2SIngo Weinhold	int count;
2978fe9f8b2SIngo Weinhold	const char* line = el_gets(fEditLine, &count);
2988fe9f8b2SIngo Weinhold
2998fe9f8b2SIngo Weinhold	fPrompt = NULL;
3008fe9f8b2SIngo Weinhold
30186b1039bSIngo Weinhold	ProcessPendingEvents();
30286b1039bSIngo Weinhold
3038fe9f8b2SIngo Weinhold	return line;
3048fe9f8b2SIngo Weinhold}
3058fe9f8b2SIngo Weinhold
3068fe9f8b2SIngo Weinhold
3078fe9f8b2SIngo Weinholdvoid
3088fe9f8b2SIngo WeinholdCliContext::AddLineToInputHistory(const char* line)
3098fe9f8b2SIngo Weinhold{
3108fe9f8b2SIngo Weinhold	HistEvent historyEvent;
3118fe9f8b2SIngo Weinhold	history(fHistory, &historyEvent, H_ENTER, line);
3128fe9f8b2SIngo Weinhold}
3138fe9f8b2SIngo Weinhold
3148fe9f8b2SIngo Weinhold
3158fe9f8b2SIngo Weinholdvoid
3168fe9f8b2SIngo WeinholdCliContext::QuitSession(bool killTeam)
3178fe9f8b2SIngo Weinhold{
318d266c87dSIngo Weinhold	_PrepareToWaitForEvents(EVENT_QUIT);
3198fe9f8b2SIngo Weinhold
3208fe9f8b2SIngo Weinhold	fListener->UserInterfaceQuitRequested(
3218fe9f8b2SIngo Weinhold		killTeam
3228fe9f8b2SIngo Weinhold			? UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM
3238fe9f8b2SIngo Weinhold			: UserInterfaceListener::QUIT_OPTION_ASK_RESUME_TEAM);
3248fe9f8b2SIngo Weinhold
325d266c87dSIngo Weinhold	_WaitForEvents();
3268fe9f8b2SIngo Weinhold}
3278fe9f8b2SIngo Weinhold
3288fe9f8b2SIngo Weinhold
3298fe9f8b2SIngo Weinholdvoid
3308fe9f8b2SIngo WeinholdCliContext::WaitForThreadOrUser()
3318fe9f8b2SIngo Weinhold{
33286b1039bSIngo Weinhold	ProcessPendingEvents();
33386b1039bSIngo Weinhold
334d266c87dSIngo Weinhold// TODO: Deal with SIGINT as well!
335d266c87dSIngo Weinhold	for (;;) {
336d266c87dSIngo Weinhold		_PrepareToWaitForEvents(
33786b1039bSIngo Weinhold			EVENT_USER_INTERRUPT | EVENT_THREAD_STOPPED);
338d266c87dSIngo Weinhold
339d266c87dSIngo Weinhold		// check whether there are any threads stopped already
34086b1039bSIngo Weinhold		Thread* stoppedThread = NULL;
34186b1039bSIngo Weinhold		BReference<Thread> stoppedThreadReference;
34286b1039bSIngo Weinhold
343d266c87dSIngo Weinhold		AutoLocker<Team> teamLocker(fTeam);
344d266c87dSIngo Weinhold
345d266c87dSIngo Weinhold		for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
346d266c87dSIngo Weinhold				Thread* thread = it.Next();) {
347d266c87dSIngo Weinhold			if (thread->State() == THREAD_STATE_STOPPED) {
34886b1039bSIngo Weinhold				stoppedThread = thread;
34986b1039bSIngo Weinhold				stoppedThreadReference.SetTo(thread);
350d266c87dSIngo Weinhold				break;
351d266c87dSIngo Weinhold			}
352d266c87dSIngo Weinhold		}
353d266c87dSIngo Weinhold
354d266c87dSIngo Weinhold		teamLocker.Unlock();
355d266c87dSIngo Weinhold
35686b1039bSIngo Weinhold		if (stoppedThread != NULL) {
35786b1039bSIngo Weinhold			if (fCurrentThread == NULL)
3581325ad5fSRene Gollent				SetCurrentThread(stoppedThread);
35986b1039bSIngo Weinhold
36086b1039bSIngo Weinhold			_SignalInputLoop(EVENT_THREAD_STOPPED);
36186b1039bSIngo Weinhold		}
362d266c87dSIngo Weinhold
363d266c87dSIngo Weinhold		uint32 events = _WaitForEvents();
36486b1039bSIngo Weinhold		if ((events & EVENT_QUIT) != 0 || stoppedThread != NULL) {
36586b1039bSIngo Weinhold			ProcessPendingEvents();
366d266c87dSIngo Weinhold			return;
36786b1039bSIngo Weinhold		}
36886b1039bSIngo Weinhold	}
36986b1039bSIngo Weinhold}
37086b1039bSIngo Weinhold
37186b1039bSIngo Weinhold
37203289a33SRene Gollentvoid
37303289a33SRene GollentCliContext::WaitForEvents(int32 eventMask)
37403289a33SRene Gollent{
37503289a33SRene Gollent	for (;;) {
37603289a33SRene Gollent		_PrepareToWaitForEvents(eventMask | EVENT_USER_INTERRUPT);
37703289a33SRene Gollent		uint32 events = fEventsOccurred;
37803289a33SRene Gollent		if ((events & eventMask) == 0) {
37903289a33SRene Gollent			events = _WaitForEvents();
38003289a33SRene Gollent		}
38103289a33SRene Gollent
38203289a33SRene Gollent		if ((events & EVENT_QUIT) != 0 || (events & eventMask) != 0) {
38303289a33SRene Gollent			_SignalInputLoop(eventMask);
38403289a33SRene Gollent			ProcessPendingEvents();
38503289a33SRene Gollent			return;
38603289a33SRene Gollent		}
38703289a33SRene Gollent	}
38803289a33SRene Gollent}
38903289a33SRene Gollent
39003289a33SRene Gollent
39186b1039bSIngo Weinholdvoid
39286b1039bSIngo WeinholdCliContext::ProcessPendingEvents()
39386b1039bSIngo Weinhold{
39486b1039bSIngo Weinhold	AutoLocker<Team> teamLocker(fTeam);
39586b1039bSIngo Weinhold
39686b1039bSIngo Weinhold	for (;;) {
39786b1039bSIngo Weinhold		// get the next event
39886b1039bSIngo Weinhold		AutoLocker<BLocker> locker(fLock);
39986b1039bSIngo Weinhold		Event* event = fPendingEvents.RemoveHead();
40086b1039bSIngo Weinhold		locker.Unlock();
40186b1039bSIngo Weinhold		if (event == NULL)
40286b1039bSIngo Weinhold			break;
40386b1039bSIngo Weinhold		ObjectDeleter<Event> eventDeleter(event);
40486b1039bSIngo Weinhold
40586b1039bSIngo Weinhold		// process the event
40686b1039bSIngo Weinhold		Thread* thread = event->GetThread();
40786b1039bSIngo Weinhold
40886b1039bSIngo Weinhold		switch (event->Type()) {
40986b1039bSIngo Weinhold			case EVENT_QUIT:
4102d9d01e2SRene Gollent			case EVENT_DEBUG_REPORT_CHANGED:
41186b1039bSIngo Weinhold			case EVENT_USER_INTERRUPT:
41286b1039bSIngo Weinhold				break;
41386b1039bSIngo Weinhold			case EVENT_THREAD_ADDED:
41486b1039bSIngo Weinhold				printf("[new thread: %" B_PRId32 " \"%s\"]\n", thread->ID(),
41586b1039bSIngo Weinhold					thread->Name());
41686b1039bSIngo Weinhold				break;
41786b1039bSIngo Weinhold			case EVENT_THREAD_REMOVED:
41886b1039bSIngo Weinhold				printf("[thread terminated: %" B_PRId32 " \"%s\"]\n",
41986b1039bSIngo Weinhold					thread->ID(), thread->Name());
42086b1039bSIngo Weinhold				break;
42186b1039bSIngo Weinhold			case EVENT_THREAD_STOPPED:
42286b1039bSIngo Weinhold				printf("[thread stopped: %" B_PRId32 " \"%s\"]\n",
42386b1039bSIngo Weinhold					thread->ID(), thread->Name());
42486b1039bSIngo Weinhold				break;
4251325ad5fSRene Gollent			case EVENT_THREAD_STACK_TRACE_CHANGED:
4261325ad5fSRene Gollent				if (thread == fCurrentThread) {
4271325ad5fSRene Gollent					fCurrentStackTrace = thread->GetStackTrace();
4281325ad5fSRene Gollent					fCurrentStackTrace->AcquireReference();
4291325ad5fSRene Gollent					SetCurrentStackFrameIndex(0);
4301325ad5fSRene Gollent				}
4311325ad5fSRene Gollent				break;
432c7f5dd62SRene Gollent			case EVENT_TEAM_MEMORY_BLOCK_RETRIEVED:
433c7f5dd62SRene Gollent				if (fCurrentBlock != NULL) {
434c7f5dd62SRene Gollent					fCurrentBlock->ReleaseReference();
435c7f5dd62SRene Gollent					fCurrentBlock = NULL;
436c7f5dd62SRene Gollent				}
437c7f5dd62SRene Gollent				fCurrentBlock = event->GetMemoryBlock();
438c7f5dd62SRene Gollent				break;
43938258751SRene Gollent			case EVENT_EXPRESSION_EVALUATED:
440d1c9ffedSRene Gollent				fExpressionResult = event->GetExpressionResult();
441d1c9ffedSRene Gollent				if (fExpressionValue != NULL) {
442d1c9ffedSRene Gollent					fExpressionValue->ReleaseReference();
443d1c9ffedSRene Gollent					fExpressionValue = NULL;
44438258751SRene Gollent				}
445d1c9ffedSRene Gollent				fExpressionValue = event->GetExpressionValue();
446d1c9ffedSRene Gollent				if (fExpressionValue != NULL)
447d1c9ffedSRene Gollent					fExpressionValue->AcquireReference();
44838258751SRene Gollent				break;
44986b1039bSIngo Weinhold		}
450d266c87dSIngo Weinhold	}
451d266c87dSIngo Weinhold}
452d266c87dSIngo Weinhold
453d266c87dSIngo Weinhold
454d266c87dSIngo Weinholdvoid
45586b1039bSIngo WeinholdCliContext::ThreadAdded(const Team::ThreadEvent& threadEvent)
456d266c87dSIngo Weinhold{
45786b1039bSIngo Weinhold	_QueueEvent(
45886b1039bSIngo Weinhold		new(std::nothrow) Event(EVENT_THREAD_ADDED, threadEvent.GetThread()));
45986b1039bSIngo Weinhold	_SignalInputLoop(EVENT_THREAD_ADDED);
46086b1039bSIngo Weinhold}
46186b1039bSIngo Weinhold
46286b1039bSIngo Weinhold
46386b1039bSIngo Weinholdvoid
46486b1039bSIngo WeinholdCliContext::ThreadRemoved(const Team::ThreadEvent& threadEvent)
46586b1039bSIngo Weinhold{
46686b1039bSIngo Weinhold	_QueueEvent(
46786b1039bSIngo Weinhold		new(std::nothrow) Event(EVENT_THREAD_REMOVED, threadEvent.GetThread()));
46886b1039bSIngo Weinhold	_SignalInputLoop(EVENT_THREAD_REMOVED);
46986b1039bSIngo Weinhold}
47086b1039bSIngo Weinhold
47186b1039bSIngo Weinhold
47286b1039bSIngo Weinholdvoid
47386b1039bSIngo WeinholdCliContext::ThreadStateChanged(const Team::ThreadEvent& threadEvent)
47486b1039bSIngo Weinhold{
47586b1039bSIngo Weinhold	if (threadEvent.GetThread()->State() != THREAD_STATE_STOPPED)
47686b1039bSIngo Weinhold		return;
47786b1039bSIngo Weinhold
47886b1039bSIngo Weinhold	_QueueEvent(
47986b1039bSIngo Weinhold		new(std::nothrow) Event(EVENT_THREAD_STOPPED, threadEvent.GetThread()));
48086b1039bSIngo Weinhold	_SignalInputLoop(EVENT_THREAD_STOPPED);
48186b1039bSIngo Weinhold}
48286b1039bSIngo Weinhold
48386b1039bSIngo Weinhold
4841325ad5fSRene Gollentvoid
4851325ad5fSRene GollentCliContext::ThreadStackTraceChanged(const Team::ThreadEvent& threadEvent)
4861325ad5fSRene Gollent{
4871325ad5fSRene Gollent	if (threadEvent.GetThread()->State() != THREAD_STATE_STOPPED)
4881325ad5fSRene Gollent		return;
4891325ad5fSRene Gollent
4901325ad5fSRene Gollent	_QueueEvent(
4911325ad5fSRene Gollent		new(std::nothrow) Event(EVENT_THREAD_STACK_TRACE_CHANGED,
4921325ad5fSRene Gollent			threadEvent.GetThread()));
4931325ad5fSRene Gollent	_SignalInputLoop(EVENT_THREAD_STACK_TRACE_CHANGED);
4941325ad5fSRene Gollent}
4951325ad5fSRene Gollent
4961325ad5fSRene Gollent
49738258751SRene Gollentvoid
498d1c9ffedSRene GollentCliContext::ExpressionEvaluated(ExpressionInfo* info, status_t result,
49981c848a1SRene Gollent	ExpressionResult* value)
50038258751SRene Gollent{
50138258751SRene Gollent	_QueueEvent(
50238258751SRene Gollent		new(std::nothrow) Event(EVENT_EXPRESSION_EVALUATED,
503d1c9ffedSRene Gollent			NULL, NULL, info, result, value));
50438258751SRene Gollent	_SignalInputLoop(EVENT_EXPRESSION_EVALUATED);
50538258751SRene Gollent}
50638258751SRene Gollent
50738258751SRene Gollent
5088b9099b1SRene Gollentvoid
5098b9099b1SRene GollentCliContext::DebugReportChanged(const Team::DebugReportEvent& event)
5108b9099b1SRene Gollent{
5117bdeef54SRene Gollent	if (event.GetFinalStatus() == B_OK) {
5127bdeef54SRene Gollent		printf("Successfully saved debug report to %s\n",
5137bdeef54SRene Gollent			event.GetReportPath());
5147bdeef54SRene Gollent	} else {
5157bdeef54SRene Gollent		fprintf(stderr, "Failed to write debug report: %s\n", strerror(
5167bdeef54SRene Gollent				event.GetFinalStatus()));
5177bdeef54SRene Gollent	}
5188b9099b1SRene Gollent
5198b9099b1SRene Gollent	_QueueEvent(new(std::nothrow) Event(EVENT_DEBUG_REPORT_CHANGED));
5208b9099b1SRene Gollent	_SignalInputLoop(EVENT_DEBUG_REPORT_CHANGED);
5218b9099b1SRene Gollent}
5228b9099b1SRene Gollent
5238b9099b1SRene Gollent
524e2d845a4SRene Gollentvoid
525e2d845a4SRene GollentCliContext::CoreFileChanged(const Team::CoreFileChangedEvent& event)
526e2d845a4SRene Gollent{
527e2d845a4SRene Gollent	printf("Successfully saved core file to %s\n",
528e2d845a4SRene Gollent		event.GetTargetPath());
529e2d845a4SRene Gollent
530e2d845a4SRene Gollent	_QueueEvent(new(std::nothrow) Event(EVENT_CORE_FILE_CHANGED));
531e2d845a4SRene Gollent	_SignalInputLoop(EVENT_CORE_FILE_CHANGED);
532e2d845a4SRene Gollent}
533e2d845a4SRene Gollent
534e2d845a4SRene Gollent
535c7f5dd62SRene Gollentvoid
536c7f5dd62SRene GollentCliContext::MemoryBlockRetrieved(TeamMemoryBlock* block)
537c7f5dd62SRene Gollent{
538c7f5dd62SRene Gollent	_QueueEvent(
539c7f5dd62SRene Gollent		new(std::nothrow) Event(EVENT_TEAM_MEMORY_BLOCK_RETRIEVED,
540c7f5dd62SRene Gollent			NULL, block));
541c7f5dd62SRene Gollent	_SignalInputLoop(EVENT_TEAM_MEMORY_BLOCK_RETRIEVED);
542c7f5dd62SRene Gollent}
543c7f5dd62SRene Gollent
544c7f5dd62SRene Gollent
54503289a33SRene Gollentvoid
54603289a33SRene GollentCliContext::ValueNodeChanged(ValueNodeChild* nodeChild, ValueNode* oldNode,
54703289a33SRene Gollent	ValueNode* newNode)
54803289a33SRene Gollent{
54903289a33SRene Gollent	_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
55003289a33SRene Gollent}
55103289a33SRene Gollent
55203289a33SRene Gollent
55303289a33SRene Gollentvoid
55403289a33SRene GollentCliContext::ValueNodeChildrenCreated(ValueNode* node)
55503289a33SRene Gollent{
55603289a33SRene Gollent	_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
55703289a33SRene Gollent}
55803289a33SRene Gollent
55903289a33SRene Gollent
56003289a33SRene Gollentvoid
56103289a33SRene GollentCliContext::ValueNodeChildrenDeleted(ValueNode* node)
56203289a33SRene Gollent{
56303289a33SRene Gollent	_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
56403289a33SRene Gollent}
56503289a33SRene Gollent
56603289a33SRene Gollent
56703289a33SRene Gollentvoid
56803289a33SRene GollentCliContext::ValueNodeValueChanged(ValueNode* oldNode)
56903289a33SRene Gollent{
57003289a33SRene Gollent	_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
57103289a33SRene Gollent}
57203289a33SRene Gollent
57303289a33SRene Gollent
57486b1039bSIngo Weinholdvoid
57586b1039bSIngo WeinholdCliContext::_QueueEvent(Event* event)
57686b1039bSIngo Weinhold{
57786b1039bSIngo Weinhold	if (event == NULL) {
57886b1039bSIngo Weinhold		// no memory -- can't do anything about it
57986b1039bSIngo Weinhold		return;
58086b1039bSIngo Weinhold	}
58186b1039bSIngo Weinhold
58286b1039bSIngo Weinhold	AutoLocker<BLocker> locker(fLock);
58386b1039bSIngo Weinhold	fPendingEvents.Add(event);
584d266c87dSIngo Weinhold}
585d266c87dSIngo Weinhold
586d266c87dSIngo Weinhold
587d266c87dSIngo Weinholdvoid
588d266c87dSIngo WeinholdCliContext::_PrepareToWaitForEvents(uint32 eventMask)
589d266c87dSIngo Weinhold{
590d266c87dSIngo Weinhold	// Set the events we're going to wait for -- always wait for "quit".
591d266c87dSIngo Weinhold	AutoLocker<BLocker> locker(fLock);
592d266c87dSIngo Weinhold	fInputLoopWaitingForEvents = eventMask | EVENT_QUIT;
593d266c87dSIngo Weinhold	fEventsOccurred = fTerminating ? EVENT_QUIT : 0;
594d266c87dSIngo Weinhold}
595d266c87dSIngo Weinhold
596d266c87dSIngo Weinhold
597d266c87dSIngo Weinholduint32
598d266c87dSIngo WeinholdCliContext::_WaitForEvents()
599d266c87dSIngo Weinhold{
600d266c87dSIngo Weinhold	AutoLocker<BLocker> locker(fLock);
601d266c87dSIngo Weinhold
602d266c87dSIngo Weinhold	if (fEventsOccurred == 0) {
603d266c87dSIngo Weinhold		sem_id blockingSemaphore = fBlockingSemaphore;
604d266c87dSIngo Weinhold		fInputLoopWaiting = true;
605d266c87dSIngo Weinhold
606d266c87dSIngo Weinhold		locker.Unlock();
607d266c87dSIngo Weinhold
608d266c87dSIngo Weinhold		while (acquire_sem(blockingSemaphore) == B_INTERRUPTED) {
609d266c87dSIngo Weinhold		}
610d266c87dSIngo Weinhold
611d266c87dSIngo Weinhold		locker.Lock();
612d266c87dSIngo Weinhold	}
613d266c87dSIngo Weinhold
614d266c87dSIngo Weinhold	uint32 events = fEventsOccurred;
615d266c87dSIngo Weinhold	fEventsOccurred = 0;
616d266c87dSIngo Weinhold	return events;
617d266c87dSIngo Weinhold}
618d266c87dSIngo Weinhold
619d266c87dSIngo Weinhold
620d266c87dSIngo Weinholdvoid
621d266c87dSIngo WeinholdCliContext::_SignalInputLoop(uint32 events)
622d266c87dSIngo Weinhold{
623d266c87dSIngo Weinhold	AutoLocker<BLocker> locker(fLock);
624d266c87dSIngo Weinhold
625d266c87dSIngo Weinhold	if ((fInputLoopWaitingForEvents & events) == 0)
626d266c87dSIngo Weinhold		return;
627d266c87dSIngo Weinhold
628d266c87dSIngo Weinhold	fEventsOccurred = fInputLoopWaitingForEvents & events;
629d266c87dSIngo Weinhold	fInputLoopWaitingForEvents = 0;
630d266c87dSIngo Weinhold
631d266c87dSIngo Weinhold	if (fInputLoopWaiting) {
632d266c87dSIngo Weinhold		fInputLoopWaiting = false;
633d266c87dSIngo Weinhold		release_sem(fBlockingSemaphore);
634d266c87dSIngo Weinhold	}
6358fe9f8b2SIngo Weinhold}
6368fe9f8b2SIngo Weinhold
6378fe9f8b2SIngo Weinhold
6388fe9f8b2SIngo Weinhold/*static*/ const char*
6398fe9f8b2SIngo WeinholdCliContext::_GetPrompt(EditLine* editLine)
640d0ef7540SIngo Weinhold{
6418fe9f8b2SIngo Weinhold	return sCurrentContext != NULL ? sCurrentContext->fPrompt : NULL;
642d0ef7540SIngo Weinhold}
643