Skip to content

Commit

Permalink
Reduce number of threads in lldb-mi.
Browse files Browse the repository at this point in the history
LLDB-mi have 3 threads.

1. Wait for input.
2. Process commands.
3. Process events.
This revision merges 1 & 2. Same thread waits on input and then process the
command. This way, no synchronization is needed between first and 2nd. Also it is
easy to check when to exit.

A lot of code will redundant and will be cleaned up gradually.

All lldb-mi tests pass with gcc and clang as test compiler. Also did minimal testing
on command line and works ok. The "quit" and "-gdb-exit" command close the application
without needing any further return.

Reviewed in http://reviews.llvm.org/D7746.



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@230003 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
abidh committed Feb 20, 2015
1 parent 9cc75ec commit 6c2281f
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 172 deletions.
1 change: 1 addition & 0 deletions tools/lldb-mi/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class Driver : public lldb::SBBroadcaster, public CMIDriverBase, public CMIDrive
virtual bool SetDriverParent(const CMIDriverBase &vrOtherDriver);
virtual const CMIUtilString &GetDriverName(void) const;
virtual const CMIUtilString &GetDriverId(void) const;
virtual void DeliverSignal(int signal) {}

// Original code:
public:
Expand Down
34 changes: 33 additions & 1 deletion tools/lldb-mi/MICmnStreamStdin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#else
#include "MICmnStreamStdinLinux.h"
#endif // defined( _MSC_VER )
#include <string.h> // For std::strerror()

//++ ------------------------------------------------------------------------------------
// Details: CMICmnStreamStdin constructor.
Expand All @@ -49,6 +50,7 @@ CMICmnStreamStdin::CMICmnStreamStdin(void)
, m_bShowPrompt(true)
, m_bRedrawPrompt(true)
, m_pStdinReadHandler(nullptr)
, m_pCmdBuffer(nullptr)
{
}

Expand Down Expand Up @@ -103,6 +105,9 @@ CMICmnStreamStdin::Initialize(void)
return MIstatus::failure;
}

if (bOk)
m_pCmdBuffer = new MIchar[m_constBufferSize];

// Other resources required
if (bOk)
{
Expand Down Expand Up @@ -142,6 +147,12 @@ CMICmnStreamStdin::Shutdown(void)

ClrErrorDescription();

if (m_pCmdBuffer != nullptr)
{
delete[] m_pCmdBuffer;
m_pCmdBuffer = nullptr;
}

bool bOk = MIstatus::success;
CMIUtilString errMsg;

Expand Down Expand Up @@ -355,7 +366,28 @@ CMICmnStreamStdin::MonitorStdin(bool &vrwbYesAlive)
const MIchar *
CMICmnStreamStdin::ReadLine(CMIUtilString &vwErrMsg)
{
return m_pStdinReadHandler->ReadLine(vwErrMsg);
vwErrMsg.clear();

// Read user input
const MIchar *pText = ::fgets(&m_pCmdBuffer[0], m_constBufferSize, stdin);
if (pText == nullptr)
{
if (::ferror(stdin) != 0)
vwErrMsg = ::strerror(errno);
return nullptr;
}

// Strip off new line characters
for (MIchar *pI = m_pCmdBuffer; *pI != '\0'; pI++)
{
if ((*pI == '\n') || (*pI == '\r'))
{
*pI = '\0';
break;
}
}

return pText;
}

//++ ------------------------------------------------------------------------------------
Expand Down
4 changes: 3 additions & 1 deletion tools/lldb-mi/MICmnStreamStdin.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class CMICmnStreamStdin : public CMICmnBase, public CMIUtilThreadActiveObjBase,
bool SetVisitor(IStreamStdin &vrVisitor);
bool SetOSStdinHandler(IOSStdinHandler &vrHandler);
void OnExitHandler(void);
const MIchar *ReadLine(CMIUtilString &vwErrMsg);

// Overridden:
public:
Expand All @@ -104,7 +105,6 @@ class CMICmnStreamStdin : public CMICmnBase, public CMIUtilThreadActiveObjBase,
void operator=(const CMICmnStreamStdin &);

bool MonitorStdin(bool &vrwbYesExit);
const MIchar *ReadLine(CMIUtilString &vwErrMsg);
bool
InputAvailable(bool &vbAvail); // Bytes are available on stdin

Expand All @@ -122,4 +122,6 @@ class CMICmnStreamStdin : public CMICmnBase, public CMIUtilThreadActiveObjBase,
bool m_bShowPrompt; // True = Yes prompt is shown/output to the user (stdout), false = no prompt
bool m_bRedrawPrompt; // True = Prompt needs to be redrawn
IOSStdinHandler *m_pStdinReadHandler;
static const int m_constBufferSize = 2048;
MIchar *m_pCmdBuffer;
};
199 changes: 43 additions & 156 deletions tools/lldb-mi/MIDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,42 +499,6 @@ CMIDriver::GetDriverIsGDBMICompatibleDriver(void) const
return true;
}

//++ ------------------------------------------------------------------------------------
// Details: Callback function for monitoring stream stdin object. Part of the visitor
// pattern.
// This function is called by the CMICmnStreamStdin::CThreadStdin
// "stdin monitor" thread (ID).
// Type: Overridden.
// Args: vStdInBuffer - (R) Copy of the current stdin line data.
// vrbYesExit - (RW) True = yes exit stdin monitoring, false = continue monitor.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMIDriver::ReadLine(const CMIUtilString &vStdInBuffer, bool &vrwbYesExit)
{
// For debugging. Update prompt show stdin is working
// printf( "%s\n", vStdInBuffer.c_str() );
// fflush( stdout );

// Special case look for the quit command here so stop monitoring stdin stream
// So we do not go back to fgetc() and wait and hang thread on exit
if (vStdInBuffer == "quit")
vrwbYesExit = true;

// 1. Put new line in the queue container by stdin monitor thread
// 2. Then *this driver calls ReadStdinLineQueue() when ready to read the queue in its
// own thread
const bool bOk = QueueMICommand(vStdInBuffer);

// Check to see if the *this driver is shutting down (exit application)
if (!vrwbYesExit)
vrwbYesExit = m_bDriverIsExiting;

return bOk;
}

//++ ------------------------------------------------------------------------------------
// Details: Start worker threads for the driver.
// Type: Method.
Expand All @@ -551,16 +515,6 @@ CMIDriver::StartWorkerThreads(void)
// Grab the thread manager
CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance();

// Start the stdin thread
bOk &= m_rStdin.SetVisitor(*this);
if (bOk && !rThreadMgr.ThreadStart<CMICmnStreamStdin>(m_rStdin))
{
const CMIUtilString errMsg = CMIUtilString::Format(MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE),
CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str());
SetErrorDescriptionn(errMsg);
return MIstatus::failure;
}

// Start the event polling thread
if (bOk && !rThreadMgr.ThreadStart<CMICmnLLDBDebugger>(m_rLldbDebugger))
{
Expand Down Expand Up @@ -627,11 +581,31 @@ CMIDriver::DoMainLoop(void)
// While the app is active
while (!m_bExitApp)
{
// Poll stdin queue and dispatch
if (!ReadStdinLineQueue())
CMIUtilString errorText;
const MIchar *pCmd = m_rStdin.ReadLine (errorText);
if (pCmd != nullptr)
{
// Something went wrong
break;
CMIUtilString lineText(pCmd);
if (!lineText.empty ())
{
if (lineText == "quit")
{
// We want to be exiting when receiving a quit command
m_bExitApp = true;
break;
}

bool bOk = false;
{
// Lock Mutex before processing commands so that we don't disturb an event
// being processed
CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
bOk = InterpretCommand(lineText);
}
// Draw prompt if desired
if (bOk && m_rStdin.GetEnablePrompt())
m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt());
}
}
}

Expand All @@ -647,72 +621,6 @@ CMIDriver::DoMainLoop(void)
return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: *this driver sits and waits for input to the stdin line queue shared by *this
// driver and the stdin monitor thread, it queues, *this reads, interprets and
// reacts.
// This function is used by the application's main thread.
// Type: Method.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMIDriver::ReadStdinLineQueue(void)
{
// True when queue contains input
bool bHaveInput = false;

// Stores the current input line
CMIUtilString lineText;
{
// Lock while we access the queue
CMIUtilThreadLock lock(m_threadMutex);
if (!m_queueStdinLine.empty())
{
lineText = m_queueStdinLine.front();
m_queueStdinLine.pop();
bHaveInput = !lineText.empty();
}
}

// Process while we have input
if (bHaveInput)
{
if (lineText == "quit")
{
// We want to be exiting when receiving a quit command
m_bExitApp = true;
return MIstatus::success;
}

// Process the command
bool bOk = false;
{
// Lock Mutex before processing commands so that we don't disturb an event
// that is being processed.
CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
bOk = InterpretCommand(lineText);
}

// Draw prompt if desired
if (bOk && m_rStdin.GetEnablePrompt())
m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt());

// Input has been processed
bHaveInput = false;
}
else
{
// Give resources back to the OS
const std::chrono::milliseconds time(1);
std::this_thread::sleep_for(time);
}

return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Set things in motion, set state etc that brings *this driver (and the
// application) to a tidy shutdown.
Expand Down Expand Up @@ -925,42 +833,6 @@ CMIDriver::GetId(void) const
return m_strDriverId;
}

//++ ------------------------------------------------------------------------------------
// Details: Inject a command into the command processing system to be interpreted as a
// command read from stdin. The text representing the command is also written
// out to stdout as the command did not come from via stdin.
// Type: Method.
// Args: vMICmd - (R) Text data representing a possible command.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMIDriver::InjectMICommand(const CMIUtilString &vMICmd)
{
const bool bOk = m_rStdOut.WriteMIResponse(vMICmd);

return bOk && QueueMICommand(vMICmd);
}

//++ ------------------------------------------------------------------------------------
// Details: Add a new command candidate to the command queue to be processed by the
// command system.
// Type: Method.
// Args: vMICmd - (R) Text data representing a possible command.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMIDriver::QueueMICommand(const CMIUtilString &vMICmd)
{
CMIUtilThreadLock lock(m_threadMutex);
m_queueStdinLine.push(vMICmd);

return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Interpret the text data and match against current commands to see if there
// is a match. If a match then the command is issued and actioned on. The
Expand Down Expand Up @@ -1093,7 +965,7 @@ CMIDriver::SetExitApplicationFlag(const bool vbForceExit)
// but halt the inferior program being debugged instead
if (m_eCurrentDriverState == eDriverState_RunningDebugging)
{
InjectMICommand("-exec-interrupt");
InterpretCommand("-exec-interrupt");
return;
}

Expand Down Expand Up @@ -1302,9 +1174,9 @@ CMIDriver::GetExecutableFileNamePathOnCmdLine(void) const
bool
CMIDriver::LocalDebugSessionStartupInjectCommands(void)
{
const CMIUtilString strCmd(CMIUtilString::Format("-file-exec-and-symbols %s", m_strCmdLineArgExecuteableFileNamePath.c_str()));

return InjectMICommand(strCmd);
const CMIUtilString strCmd(CMIUtilString::Format("-file-exec-and-symbols \"%s\"", m_strCmdLineArgExecuteableFileNamePath.c_str()));
const bool bOk = CMICmnStreamStdout::TextToStdout(strCmd);
return (bOk && InterpretCommand(strCmd));
}

//++ ------------------------------------------------------------------------------------
Expand Down Expand Up @@ -1335,3 +1207,18 @@ CMIDriver::IsDriverDebuggingArgExecutable(void) const
{
return m_bDriverDebuggingArgExecutable;
}

//++ ------------------------------------------------------------------------------------
// Details: Gets called when lldb-mi gets a signal. Stops the process if it was SIGINT.
//
// Type: Method.
// Args: signal that was delivered
// Return: None.
// Throws: None.
//--
void
CMIDriver::DeliverSignal(int signal)
{
if (signal == SIGINT && (m_eCurrentDriverState == eDriverState_RunningDebugging))
InterpretCommand("-exec-interrupt");
}
Loading

0 comments on commit 6c2281f

Please sign in to comment.